diff --git a/.github/workflows/jnigen.yaml b/.github/workflows/jnigen.yaml new file mode 100644 index 000000000..2deae7f80 --- /dev/null +++ b/.github/workflows/jnigen.yaml @@ -0,0 +1,428 @@ +# 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. + +# Note: There's a script under `jnigen/tool` which runs a subset of these +# tests on local machine. It's a useful little script for checking the +# code before making a PR. If you add a task here, you might want to add +# the equivalent in that script as well. + +name: Dart CI + +on: + # Run on PRs and pushes to the default branch. + push: + branches: [main] + paths: + - '.github/workflows/jnigen.yaml' + - 'pkgs/jnigen/**' + - 'pkgs/jni/**' + pull_request: + branches: [main] + paths: + - '.github/workflows/jnigen.yaml' + - 'pkgs/jnigen/**' + - 'pkgs/jni/**' + schedule: + - cron: '0 0 * * 0' + +env: + PUB_ENVIRONMENT: bot.github + +jobs: + analyze_jnigen: + runs-on: ubuntu-latest + defaults: + run: + working-directory: ./pkgs/jnigen + strategy: + fail-fast: false + matrix: + sdk: [stable] + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: subosito/flutter-action@2783a3f08e1baf891508463f8c6653c258246225 + with: + channel: ${{ matrix.sdk }} + cache: true + cache-key: 'flutter-:os:-:channel:-:version:-:arch:-:hash:' + - uses: axel-op/googlejavaformat-action@fe78db8a90171b6a836449f8d0e982d5d71e5c5a + name: 'Check Java formatting with google-java-format' + with: + args: '--set-exit-if-changed' + - id: install + name: Install dependencies + run: dart pub get + - name: install dependencies for android test runner + run: flutter pub get + working-directory: ./pkgs/jnigen/android_test_runner + - name: Check formatting + run: dart format --output=none --set-exit-if-changed . + if: always() && steps.install.outcome == 'success' + - name: Analyze code + run: flutter analyze --fatal-infos + if: always() && steps.install.outcome == 'success' + + test_jnigen: + needs: [analyze_jnigen] + runs-on: ${{ matrix.os }} + defaults: + run: + working-directory: ./pkgs/jnigen + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest] + sdk: [stable, beta] + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: subosito/flutter-action@2783a3f08e1baf891508463f8c6653c258246225 + with: + channel: ${{ matrix.sdk }} + cache: true + cache-key: 'flutter-:os:-:channel:-:version:-:arch:-:hash:' + - uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 + with: + distribution: 'zulu' + java-version: '11' + cache: maven + ## Committed bindings are formatted with clang-format. + ## So this is required to format generated bindings identically + - name: install clang tools + run: | + sudo apt-get update -y + sudo apt-get install -y clang-format + - name: Install dependencies + run: dart pub get + - name: build in_app_java APK + run: flutter build apk --target-platform=android-arm64 + working-directory: ./pkgs/jnigen/example/in_app_java + - name: build notification_plugin example APK + run: flutter build apk --target-platform=android-arm64 + working-directory: ./pkgs/jnigen/example/notification_plugin/example + - name: Run summarizer tests + run: mvn surefire:test + working-directory: ./pkgs/jnigen/java + - name: Build summarizer + run: dart run jnigen:setup + - name: Generate runtime tests + run: dart run tool/generate_runtime_tests.dart + - name: Run VM tests + run: dart test --test-randomize-ordering-seed random + - name: Install coverage + run: dart pub global activate coverage + - name: Collect coverage + run: dart pub global run coverage:test_with_coverage + - name: Upload coverage + uses: coverallsapp/github-action@3dfc5567390f6fa9267c0ee9c251e4c8c3f18949 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + flag-name: jnigen_tests + parallel: true + path-to-lcov: ./pkgs/jnigen/coverage/lcov.info + if: ${{ matrix.sdk == 'stable' }} + + analyze_jni: + runs-on: ubuntu-latest + defaults: + run: + working-directory: ./pkgs/jni + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: subosito/flutter-action@2783a3f08e1baf891508463f8c6653c258246225 + with: + channel: 'stable' + cache: true + cache-key: 'flutter-:os:-:channel:-:version:-:arch:-:hash:' + - uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 + with: + distribution: 'zulu' + java-version: '11' + - uses: axel-op/googlejavaformat-action@fe78db8a90171b6a836449f8d0e982d5d71e5c5a + name: 'Check Java formatting with google-java-format' + with: + args: '--set-exit-if-changed' + - name: install clang tools & CMake + run: | + sudo apt-get update -y + sudo apt-get install -y clang-format build-essential cmake + - run: flutter pub get + - name: Check formatting + run: dart format --output=none --set-exit-if-changed . + - name: Run lints + run: flutter analyze --fatal-infos + - name: Check C code formatting using clang-format + run: clang-format --dry-run -Werror dartjni.c dartjni.h third_party/*.c third_party/*.h + working-directory: ./pkgs/jni/src + - name: verify that tool/generate_ide_files.dart generates a file + run: | + dart run tool/generate_ide_files.dart + ls src/compile_commands.json + + test_jni: + runs-on: ubuntu-latest + needs: [analyze_jni] + defaults: + run: + working-directory: ./pkgs/jni + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: subosito/flutter-action@2783a3f08e1baf891508463f8c6653c258246225 + with: + channel: 'stable' + cache: true + cache-key: 'flutter-:os:-:channel:-:version:-:arch:-:hash:' + - uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 + with: + distribution: 'zulu' + java-version: '11' + - run: | + sudo apt-get update -y + sudo apt-get install -y ninja-build libgtk-3-dev libclang-dev + - run: dart pub get + - run: dart run jni:setup + - name: Get dependencies + run: dart pub get + - name: Run tests + run: dart test --test-randomize-ordering-seed random + - name: Install coverage + run: dart pub global activate coverage + - name: Collect coverage + run: dart pub global run coverage:test_with_coverage + - name: Upload coverage + uses: coverallsapp/github-action@3dfc5567390f6fa9267c0ee9c251e4c8c3f18949 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + flag-name: jni_tests + parallel: true + path-to-lcov: ./pkgs/jni/coverage/lcov.info + # TODO(https://github.com/dart-lang/ffigen/issues/555): Ffigen generated + # on my machine has macOS specific stuff and CI does not. + # We should just generate the struct as opaque, but we currently can't. + # + # - name: regenerate & compare ffigen bindings + # ## Use git to verify no source files have changed + # run: | + # dart run tool/generate_ffi_bindings.dart + # git diff --exit-code -- lib/src/third_party src/third_party + + ## Run tests for package:jni on windows, just to confirm it works. + ## Do not, for example, collect coverage or check formatting. + test_jni_windows_minimal: + needs: [analyze_jni] + runs-on: windows-latest + defaults: + run: + working-directory: ./pkgs/jni + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: subosito/flutter-action@2783a3f08e1baf891508463f8c6653c258246225 + with: + channel: 'stable' + cache: true + cache-key: 'flutter-:os:-:channel:-:version:-:arch:-:hash:' + - uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 + with: + distribution: 'zulu' + java-version: '11' + - run: Add-Content $env:GITHUB_PATH "$env:JAVA_HOME\bin\server" + - run: dart pub get + - run: dart run jni:setup + - run: dart test --test-randomize-ordering-seed random + + test_jnigen_windows_minimal: + needs: [analyze_jnigen] + runs-on: windows-latest + defaults: + run: + working-directory: ./pkgs/jnigen + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - name: Setup clang + uses: egor-tensin/setup-clang@ef434b41eb33a70396fb336b1bae39c76d740c3d + with: + version: latest + platform: x64 + - uses: subosito/flutter-action@2783a3f08e1baf891508463f8c6653c258246225 + with: + channel: 'stable' + cache: true + cache-key: 'flutter-:os:-:channel:-:version:-:arch:-:hash:' + - uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 + with: + distribution: 'zulu' + java-version: '11' + - run: git config --global core.autocrlf true + - run: Add-Content $env:GITHUB_PATH "$env:JAVA_HOME\bin\server" + - run: dart pub get + - run: dart run jnigen:setup + - name: Build summarizer + run: dart run jnigen:setup + - name: Generate runtime tests + run: dart run tool/generate_runtime_tests.dart + - name: Run tests + run: dart test --test-randomize-ordering-seed random + + test_jni_macos_minimal: + needs: [analyze_jni] + runs-on: macos-latest + defaults: + run: + working-directory: ./pkgs/jni + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: subosito/flutter-action@2783a3f08e1baf891508463f8c6653c258246225 + with: + channel: 'stable' + cache: true + cache-key: 'flutter-:os:-:channel:-:version:-:arch:-:hash:' + - uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 + with: + distribution: 'temurin' + java-version: '11' + - run: dart pub get + - run: dart run jni:setup + - run: dart test --test-randomize-ordering-seed random + + test_jnigen_macos_minimal: + needs: [analyze_jnigen] + runs-on: macos-latest + defaults: + run: + working-directory: ./pkgs/jnigen + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - name: Setup clang format + uses: ConorMacBride/install-package@3e7ad059e07782ee54fa35f827df52aae0626f30 + with: + brew: clang-format + - uses: subosito/flutter-action@2783a3f08e1baf891508463f8c6653c258246225 + with: + channel: 'stable' + cache: true + cache-key: 'flutter-:os:-:channel:-:version:-:arch:-:hash:' + - uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 + with: + distribution: 'temurin' + java-version: '11' + - run: git config --global core.autocrlf true + - run: dart pub get + - name: Build summarizer + run: dart run jnigen:setup + - name: Generate runtime tests + run: dart run tool/generate_runtime_tests.dart + - name: Run tests + run: dart test --test-randomize-ordering-seed random + + build_jni_example_linux: + runs-on: ubuntu-latest + defaults: + run: + working-directory: ./pkgs/jni/example + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: subosito/flutter-action@2783a3f08e1baf891508463f8c6653c258246225 + with: + channel: 'stable' + cache: true + cache-key: 'flutter-:os:-:channel:-:version:-:arch:-:hash:' + - uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 + with: + distribution: 'zulu' + java-version: '11' + - run: | + sudo apt-get update -y + sudo apt-get install -y ninja-build libgtk-3-dev + - run: flutter config --enable-linux-desktop + - run: flutter pub get + - run: dart run jni:setup + - run: flutter build linux + + build_jni_example_windows: + runs-on: windows-latest + defaults: + run: + working-directory: ./pkgs/jni/example + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: subosito/flutter-action@2783a3f08e1baf891508463f8c6653c258246225 + with: + channel: 'stable' + cache: true + cache-key: 'flutter-:os:-:channel:-:version:-:arch:-:hash:' + - uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 + with: + distribution: 'zulu' + java-version: '11' + - run: flutter config --enable-windows-desktop + - run: flutter pub get + - run: flutter build windows + + build_jni_example_android: + runs-on: ubuntu-latest + defaults: + run: + working-directory: ./pkgs/jni/example + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 + with: + distribution: 'zulu' + java-version: '11' + - uses: subosito/flutter-action@2783a3f08e1baf891508463f8c6653c258246225 + with: + channel: 'stable' + cache: true + cache-key: 'flutter-:os:-:channel:-:version:-:arch:-:hash:' + - run: flutter pub get + - run: flutter build apk + + run_pdfbox_example_linux: + runs-on: ubuntu-latest + defaults: + run: + working-directory: ./pkgs/jnigen/example/pdfbox_plugin + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: subosito/flutter-action@2783a3f08e1baf891508463f8c6653c258246225 + with: + channel: 'stable' + cache: true + cache-key: 'flutter-:os:-:channel:-:version:-:arch:-:hash:' + - uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 + with: + distribution: 'zulu' + java-version: '11' + - run: | + sudo apt-get update -y + sudo apt-get install -y ninja-build libgtk-3-dev clang-format + - run: flutter config --enable-linux-desktop + - run: dart pub get + - name: Generate full bindings + run: dart run jnigen --config jnigen.yaml --override classes="org.apache.pdfbox" + - name: Analyze generated bindings + run: | + flutter pub get # dart-analyze errors on flutter example + flutter analyze + - name: Run standalone example + run: | + dart pub get + dart run jni:setup + wget 'https://dart.dev/guides/language/specifications/DartLangSpec-v2.2.pdf' + dart run bin/pdf_info.dart DartLangSpec-v2.2.pdf + working-directory: ./pkgs/jnigen/example/pdfbox_plugin/dart_example + - name: Build flutter example for pdfbox_plugin + run: | + flutter pub get + flutter build linux + working-directory: ./pkgs/jnigen/example/pdfbox_plugin/example + + coveralls_finish: + needs: [test_jnigen, test_jni] + runs-on: ubuntu-latest + steps: + - name: Coveralls finished + uses: coverallsapp/github-action@3dfc5567390f6fa9267c0ee9c251e4c8c3f18949 + with: + github-token: ${{ secrets.github_token }} + parallel-finished: true diff --git a/pkgs/jni/.gitignore b/pkgs/jni/.gitignore new file mode 100644 index 000000000..ae8c6c2ef --- /dev/null +++ b/pkgs/jni/.gitignore @@ -0,0 +1,32 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +.packages +build/ + +.vscode/ \ No newline at end of file diff --git a/pkgs/jni/.metadata b/pkgs/jni/.metadata new file mode 100644 index 000000000..26fc23fe6 --- /dev/null +++ b/pkgs/jni/.metadata @@ -0,0 +1,39 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled. + +version: + revision: 676cefaaff197f27424942307668886253e1ec35 + channel: stable + +project_type: plugin_ffi + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 676cefaaff197f27424942307668886253e1ec35 + base_revision: 676cefaaff197f27424942307668886253e1ec35 + - platform: android + create_revision: 676cefaaff197f27424942307668886253e1ec35 + base_revision: 676cefaaff197f27424942307668886253e1ec35 + - platform: linux + create_revision: 676cefaaff197f27424942307668886253e1ec35 + base_revision: 676cefaaff197f27424942307668886253e1ec35 + - platform: macos + create_revision: 676cefaaff197f27424942307668886253e1ec35 + base_revision: 676cefaaff197f27424942307668886253e1ec35 + - platform: windows + create_revision: 676cefaaff197f27424942307668886253e1ec35 + base_revision: 676cefaaff197f27424942307668886253e1ec35 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/pkgs/jni/CHANGELOG.md b/pkgs/jni/CHANGELOG.md new file mode 100644 index 000000000..2065bb14b --- /dev/null +++ b/pkgs/jni/CHANGELOG.md @@ -0,0 +1,84 @@ +## 0.8.0-wip + +- **Breaking Change** ([#394](https://github.com/dart-lang/jnigen/issues/394)): + Converted various `Exception`s into `Error`s: + - `UseAfterReleaseException` -> `UseAfterReleaseError` + - `DoubleReleaseException` -> `DoubleReleaseError` + - `SpawnException` -> `JniError` (It's now a `sealed class`) + - `JNullException` -> `JNullError` + - `InvalidCallTypeException` -> `InvalidCallTypeError` + - `HelperNotFoundException` -> `HelperNotFoundError` + - `JvmExistsException` -> `JniVmExistsError` + - `NoJvmInstanceException` -> `NoJvmInstanceError` +- **Breaking Change**: Removed `InvalidJStringException`. +- **Breaking Change**: The default return `callType` of type parameter `int` for + methods such as `JObject.callMethodByName` is now Java's `long` instead + of `int` to be consistent with the way arguments work. +- **Breaking Change**: `JType` is now `sealed`. +- **Breaking Change**: Primitive types and their type classes are now `final`. +- **Breaking Change**: `JArray.filled` now uses the generated type class of the + `fill` object and not its Java runtime type. + +## 0.7.2 +- Fixed a bug where reading non-null terminated strings would overflow. + +## 0.7.1 +- Removed macOS Flutter plugin until package:jni supports it ([#41](https://github.com/dart-lang/jnigen/issues/41)). + +## 0.7.0 + +- **Breaking Change** ([#387](https://github.com/dart-lang/jnigen/issues/387)): + Added `JBuffer` and `JByteBuffer` classes as default classes for + `java.nio.Buffer` and `java.nio.ByteBuffer` respectively. +- **Breaking Change**: Made the type classes `final`. +- Fixed a bug where `addAll`, `removeAll` and `retainAll` in `JSet` would run + their respective operation twice. +- Fixed a bug where `JList.insertAll` would not throw the potentially thrown + Java exception. + +## 0.6.1 + +- Depend on the stable version of Dart 3.1. + +## 0.6.0 + +- **Breaking Change** ([#131](https://github.com/dart-lang/jnigen/issues/131)): + Renamed `delete*` to `release*`. +- Added `PortProxy` and related methods used for interface implementation. +- Added the missing binding for `java.lang.Character`. + +## 0.5.0 + +- **Breaking Change** ([#137](https://github.com/dart-lang/jnigen/issues/137)): + Java primitive types are now all lowercase like `jint`, `jshort`, ... +- The bindings for `java.util.Set`, `java.util.Map`, `java.util.List` and the + numeric types like `java.lang.Integer`, `java.lang.Boolean`, ... are now + included in `package:jni`. + +## 0.4.0 + +- Type classes now have `superCount` and `superType` getters used for type + inference. + +## 0.3.0 + +- Added `PortContinuation` used for `suspend fun` in Kotlin. +- `dartjni` now depends on `dart_api_dl.h`. + +## 0.2.1 + +- Added `.clang-format` to pub. + +## 0.2.0 + +- Added array support +- Added generic support +- `JniX` turned into `JX` for a more terse code. + +## 0.1.1 + +- Windows support for running tests and examples on development machines. + +## 0.1.0 + +- Initial version: Android and Linux support, JObject API diff --git a/pkgs/jni/LICENSE b/pkgs/jni/LICENSE new file mode 100644 index 000000000..33474aad6 --- /dev/null +++ b/pkgs/jni/LICENSE @@ -0,0 +1,27 @@ +Copyright 2022, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/pkgs/jni/README.md b/pkgs/jni/README.md new file mode 100644 index 000000000..37f5b367c --- /dev/null +++ b/pkgs/jni/README.md @@ -0,0 +1,18 @@ +# jni + +This is a support library to access JNI from Dart / Flutter code. This provides the common infrastructure to bindings generated by [jnigen](https://pub.dev/packages/jnigen), as well as some utility methods. + +This library contains: + +* Functions to access the JNIEnv and JavaVM variables from JNI, and wrapper functions to those provided by JNI. JNIEnv is exposed via `GlobalJniEnv` type which provides a thin abstraction over JNIEnv, so that it can be used from multiple threads. +* Functions to spawn a JVM on desktop platforms (`Jni.spawn`). +* Some Android-specific helpers (get application context and current activity references). +* `JObject` class, which provides base class for classes generated by jnigen. +* Commonly used Java classes like `JList`, `JMap`, `JInteger`, ... + +Apart from being the base library for code generated by `jnigen` this can also be used for one-off uses of the JNI and debugging. __To generate type-safe bindings from Java libraries, use `jnigen`.__ + +## Documentation +The test/ directory contains files with comments explaining the basics of this module, and the example/ directory contains a flutter example which also touches some Android-specifics. + +Using this library assumes some familiarity with JNI - it's threading model and object references, among other things. diff --git a/pkgs/jni/analysis_options.yaml b/pkgs/jni/analysis_options.yaml new file mode 100644 index 000000000..e591be846 --- /dev/null +++ b/pkgs/jni/analysis_options.yaml @@ -0,0 +1,13 @@ +include: package:flutter_lints/flutter.yaml + +analyzer: + exclude: [build/**, third_party/**] + language: + strict-raw-types: true + +linter: + rules: + - prefer_final_locals + - prefer_const_declarations +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/pkgs/jni/android/.gitignore b/pkgs/jni/android/.gitignore new file mode 100644 index 000000000..161bdcdaf --- /dev/null +++ b/pkgs/jni/android/.gitignore @@ -0,0 +1,9 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures +.cxx diff --git a/pkgs/jni/android/README.md b/pkgs/jni/android/README.md new file mode 100644 index 000000000..7d56c6993 --- /dev/null +++ b/pkgs/jni/android/README.md @@ -0,0 +1 @@ +This folder contains the [Android plugin class](src/main/java/com/github/dart_lang/jni/JniPlugin.java) which takes care of initializing JNI on Android. diff --git a/pkgs/jni/android/build.gradle b/pkgs/jni/android/build.gradle new file mode 100644 index 000000000..3f650e845 --- /dev/null +++ b/pkgs/jni/android/build.gradle @@ -0,0 +1,89 @@ +// The Android Gradle Plugin builds the native code with the Android NDK. + +group 'com.github.dart_lang.jni' +version '1.0' + +buildscript { + ext.kotlin_version = '1.6.10' + repositories { + google() + mavenCentral() + } + + dependencies { + // The Android Gradle Plugin knows how to build native code with the NDK. + classpath 'com.android.tools.build:gradle:7.1.2' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +rootProject.allprojects { + repositories { + google() + mavenCentral() + } +} + +apply plugin: 'com.android.library' + +android { + // Keeping the classes from being removed by proguard. + defaultConfig { + consumerProguardFiles 'consumer-rules.pro' + } + buildTypes { + release { + minifyEnabled false + } + } + + // Condition for namespace compatibility in AGP 8 + if (project.android.hasProperty("namespace")) { + namespace 'com.github.dart_lang.jni' + } + + // Adding [PortContinuation] and [PortProxy] classes shared between Flutter and + // Dart-standalone versions of package:jni. + sourceSets { + main { + java { + srcDirs '../java/src/main/java' + } + } + } + + // Bumping the plugin compileSdkVersion requires all clients of this plugin + // to bump the version in their app. + compileSdkVersion 31 + + // Bumping the plugin ndkVersion requires all clients of this plugin to bump + // the version in their app and to download a newer version of the NDK. + // Note(MaheshH) - Flutter seems to download minimum NDK of flutter when + // below line is commented out. + // How about leaving it? + // ndkVersion "21.1.6352462" + + // Invoke the shared CMake build with the Android Gradle Plugin. + externalNativeBuild { + cmake { + path "../src/CMakeLists.txt" + + // The default CMake version for the Android Gradle Plugin is 3.10.2. + // https://developer.android.com/studio/projects/install-ndk#vanilla_cmake + // + // The Flutter tooling requires that developers have CMake 3.10 or later + // installed. You should not increase this version, as doing so will cause + // the plugin to fail to compile for some customers of the plugin. + // version "3.10.2" + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + defaultConfig { + minSdkVersion 16 + } +} diff --git a/pkgs/jni/android/consumer-rules.pro b/pkgs/jni/android/consumer-rules.pro new file mode 100644 index 000000000..269e42125 --- /dev/null +++ b/pkgs/jni/android/consumer-rules.pro @@ -0,0 +1 @@ +-keep class com.github.dart_lang.jni.** { *; } diff --git a/pkgs/jni/android/settings.gradle b/pkgs/jni/android/settings.gradle new file mode 100644 index 000000000..ac55455a7 --- /dev/null +++ b/pkgs/jni/android/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'jni' diff --git a/pkgs/jni/android/src/main/AndroidManifest.xml b/pkgs/jni/android/src/main/AndroidManifest.xml new file mode 100644 index 000000000..9a6646fae --- /dev/null +++ b/pkgs/jni/android/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ + + diff --git a/pkgs/jni/android/src/main/java/com/github/dart_lang/jni/JniPlugin.java b/pkgs/jni/android/src/main/java/com/github/dart_lang/jni/JniPlugin.java new file mode 100644 index 000000000..d3a1ebe78 --- /dev/null +++ b/pkgs/jni/android/src/main/java/com/github/dart_lang/jni/JniPlugin.java @@ -0,0 +1,60 @@ +// 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.jni; + +import android.app.Activity; +import android.content.Context; +import androidx.annotation.NonNull; +import io.flutter.embedding.engine.plugins.FlutterPlugin; +import io.flutter.embedding.engine.plugins.activity.ActivityAware; +import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding; +import io.flutter.plugin.common.PluginRegistry.Registrar; + +public class JniPlugin implements FlutterPlugin, ActivityAware { + + @Override + public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) { + setup(binding.getApplicationContext()); + } + + public static void registerWith(Registrar registrar) { + JniPlugin plugin = new JniPlugin(); + plugin.setup(registrar.activeContext()); + } + + private void setup(Context context) { + initializeJni(context, getClass().getClassLoader()); + } + + @Override + public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {} + + // Activity handling methods + @Override + public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) { + Activity activity = binding.getActivity(); + setJniActivity(activity, activity.getApplicationContext()); + } + + @Override + public void onDetachedFromActivityForConfigChanges() {} + + @Override + public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) { + Activity activity = binding.getActivity(); + setJniActivity(activity, activity.getApplicationContext()); + } + + @Override + public void onDetachedFromActivity() {} + + native void initializeJni(Context context, ClassLoader classLoader); + + native void setJniActivity(Activity activity, Context context); + + static { + System.loadLibrary("dartjni"); + } +} diff --git a/pkgs/jni/bin/setup.dart b/pkgs/jni/bin/setup.dart new file mode 100644 index 000000000..7727cc148 --- /dev/null +++ b/pkgs/jni/bin/setup.dart @@ -0,0 +1,262 @@ +// 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. + +import 'dart:io'; + +import 'package:args/args.dart'; +import 'package:package_config/package_config.dart'; + +import 'package:jni/src/build_util/build_util.dart'; + +const jniNativeBuildDirective = + '# jni_native_build (Build with jni:setup. Do not delete this line.)'; + +// When changing this constant here, also change corresponding path in +// test/test_util. +const _defaultRelativeBuildPath = "build/jni_libs"; + +const _buildPath = "build-path"; +const _srcPath = "add-source"; +const _packageName = 'add-package'; +const _verbose = "verbose"; +const _cmakeArgs = "cmake-args"; + +Future runCommand( + String exec, List args, String workingDir) async { + // For printing relative path always. + var current = Directory.current.path; + if (!current.endsWith(Platform.pathSeparator)) { + current += Platform.pathSeparator; + } + if (workingDir.startsWith(current)) { + workingDir.replaceFirst(current, ""); + } + + final cmd = "$exec ${args.join(" ")}"; + stderr.writeln("+ [$workingDir] $cmd"); + int status; + if (options.verbose) { + final process = await Process.start( + exec, args, + workingDirectory: workingDir, + mode: ProcessStartMode.inheritStdio, + // without `runInShell`, sometimes cmake doesn't run on windows. + runInShell: true, + ); + status = await process.exitCode; + if (status != 0) { + exitCode = status; + } + } else { + // ProcessStartMode.normal sometimes hangs on windows. No idea why. + final process = await Process.run(exec, args, + runInShell: true, workingDirectory: workingDir); + status = process.exitCode; + if (status != 0) { + exitCode = status; + var out = process.stdout; + var err = process.stderr; + if (stdout.supportsAnsiEscapes) { + out = "$ansiRed$out$ansiDefault"; + err = "$ansiRed$err$ansiDefault"; + } + stdout.writeln(out); + stderr.writeln(err); + } + } + if (status != 0) { + stderr.writeln('Command exited with status code $status'); + } +} + +class Options { + Options(ArgResults arg) + : buildPath = arg[_buildPath], + sources = arg[_srcPath], + packages = arg[_packageName], + cmakeArgs = arg[_cmakeArgs], + verbose = arg[_verbose] ?? false; + + String? buildPath; + List sources; + List packages; + List cmakeArgs; + bool verbose; +} + +late Options options; + +void verboseLog(String msg) { + if (options.verbose) { + stderr.writeln(msg); + } +} + +/// Find path to C or Java sources in pub cache for package specified by +/// [packageName]. +/// +/// If package cannot be found, null is returned. +Future findSources(String packageName, String subDirectory) async { + final packageConfig = await findPackageConfig(Directory.current); + if (packageConfig == null) { + throw UnsupportedError("Please run from project root."); + } + final package = packageConfig[packageName]; + if (package == null) { + throw UnsupportedError("Cannot find package: $packageName"); + } + return package.root.resolve(subDirectory).toFilePath(); +} + +/// Return '/src' directories of all dependencies which has a CMakeLists.txt +/// file. +Future> findDependencySources() async { + final packageConfig = await findPackageConfig(Directory.current); + if (packageConfig == null) { + throw UnsupportedError("Please run the command from project root."); + } + final sources = {}; + for (var package in packageConfig.packages) { + final src = package.root.resolve("src/"); + final cmakeLists = src.resolve("CMakeLists.txt"); + final cmakeListsFile = File.fromUri(cmakeLists); + if (cmakeListsFile.existsSync()) { + final firstLine = cmakeListsFile.readAsLinesSync().first; + if (firstLine == jniNativeBuildDirective) { + sources[package.name] = src.toFilePath(); + } + } + } + return sources; +} + +/// Returns the name of file built using sources in [cDir] +String getTargetName(Directory cDir) { + for (final file in cDir.listSync(recursive: true)) { + if (file.path.endsWith(".c")) { + final cFileName = file.uri.pathSegments.last; + final librarySuffix = Platform.isWindows ? "dll" : "so"; + return cFileName.substring(0, cFileName.length - 1) + librarySuffix; + } + } + throw Exception("Could not find a C file in ${cDir.path}"); +} + +void main(List arguments) async { + final parser = ArgParser() + ..addOption(_buildPath, + abbr: 'b', help: 'Directory to place built artifacts') + ..addMultiOption(_srcPath, + abbr: 's', help: 'alternative path to package:jni sources') + ..addMultiOption(_packageName, + abbr: 'p', + help: 'package for which native' + 'library should be built') + ..addFlag(_verbose, abbr: 'v', help: 'Enable verbose output') + ..addMultiOption(_cmakeArgs, + abbr: 'm', help: 'Pass additional argument to CMake'); + final argResults = parser.parse(arguments); + options = Options(argResults); + final rest = argResults.rest; + + if (rest.isNotEmpty) { + stderr.writeln("one or more unrecognized arguments: $rest"); + stderr.writeln("usage: dart run jni:setup "); + stderr.writeln(parser.usage); + exitCode = 1; + return; + } + + final sources = options.sources; + for (var packageName in options.packages) { + // It's assumed C FFI sources are in "src/" relative to package root. + sources.add(await findSources(packageName, 'src')); + } + if (sources.isEmpty) { + final dependencySources = await findDependencySources(); + stderr.writeln("selecting source directories for dependencies: " + "${dependencySources.keys}"); + sources.addAll(dependencySources.values); + } else { + stderr.writeln("selecting source directories: $sources"); + } + if (sources.isEmpty) { + stderr.writeln('No source paths to build!'); + exitCode = 1; + return; + } + + final currentDirUri = Uri.directory("."); + final buildPath = options.buildPath ?? + currentDirUri.resolve(_defaultRelativeBuildPath).toFilePath(); + final buildDir = Directory(buildPath); + await buildDir.create(recursive: true); + + final javaSrc = await findSources('jni', 'java'); + final targetJar = File.fromUri(buildDir.uri.resolve('jni.jar')); + if (!needsBuild(targetJar, Directory.fromUri(Uri.directory(javaSrc)))) { + verboseLog('Last modified of ${targetJar.path}: ' + '${targetJar.lastModifiedSync()}.'); + stderr.writeln('Target newer than source, skipping build.'); + } else { + verboseLog('Running mvn package for jni java sources to $buildPath.'); + await runCommand( + 'mvn', + ['package', '-Dtarget=${buildDir.absolute.path}'], + await findSources('jni', 'java'), + ); + } + + for (var srcPath in sources) { + final srcDir = Directory(srcPath); + if (!srcDir.existsSync()) { + stderr.writeln('Directory $srcPath does not exist'); + exitCode = 1; + return; + } + + verboseLog("srcPath: $srcPath"); + verboseLog("buildPath: $buildPath"); + + final targetFileUri = buildDir.uri.resolve(getTargetName(srcDir)); + final targetFile = File.fromUri(targetFileUri); + if (!needsBuild(targetFile, srcDir)) { + verboseLog("Last modified of ${targetFile.path}: " + "${targetFile.lastModifiedSync()}."); + stderr.writeln('Target newer than source, skipping build.'); + continue; + } + + // Note: creating temp dir in .dart_tool/jni instead of SystemTemp + // because latter can fail tests on Windows CI, when system temp is on + // separate drive or something. + final jniDirUri = Uri.directory(".dart_tool").resolve("jni"); + final jniDir = Directory.fromUri(jniDirUri); + await jniDir.create(recursive: true); + final tempDir = await jniDir.createTemp("jni_native_build_"); + final cmakeArgs = []; + cmakeArgs.addAll(options.cmakeArgs); + // Pass absolute path of srcDir because cmake command is run in temp dir + cmakeArgs.add(srcDir.absolute.path); + await runCommand("cmake", cmakeArgs, tempDir.path); + await runCommand("cmake", ["--build", "."], tempDir.path); + final dllDirUri = + Platform.isWindows ? tempDir.uri.resolve("Debug") : tempDir.uri; + final dllDir = Directory.fromUri(dllDirUri); + for (var entry in dllDir.listSync()) { + verboseLog(entry.toString()); + final dllSuffix = Platform.isWindows + ? "dll" + : Platform.isMacOS + ? "dylib" + : "so"; + if (entry.path.endsWith(dllSuffix)) { + final dllName = entry.uri.pathSegments.last; + final target = buildDir.uri.resolve(dllName); + entry.renameSync(target.toFilePath()); + } + } + await tempDir.delete(recursive: true); + } +} diff --git a/pkgs/jni/dart_test.yaml b/pkgs/jni/dart_test.yaml new file mode 100644 index 000000000..361ada42e --- /dev/null +++ b/pkgs/jni/dart_test.yaml @@ -0,0 +1,7 @@ +## Copyright (c) 2023, 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. + +tags: + load_test: + timeout: 10x diff --git a/pkgs/jni/example/.gitignore b/pkgs/jni/example/.gitignore new file mode 100644 index 000000000..a8e938c08 --- /dev/null +++ b/pkgs/jni/example/.gitignore @@ -0,0 +1,47 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/pkgs/jni/example/README.md b/pkgs/jni/example/README.md new file mode 100644 index 000000000..583f96056 --- /dev/null +++ b/pkgs/jni/example/README.md @@ -0,0 +1,3 @@ +# jni_example +Demonstrates how to use the jni plugin. + diff --git a/pkgs/jni/example/analysis_options.yaml b/pkgs/jni/example/analysis_options.yaml new file mode 100644 index 000000000..7f0b15f4f --- /dev/null +++ b/pkgs/jni/example/analysis_options.yaml @@ -0,0 +1,36 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +analyzer: + exclude: [build/**] + language: + strict-raw-types: true + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + - prefer_final_locals + - prefer_const_declarations + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/pkgs/jni/example/android/.gitignore b/pkgs/jni/example/android/.gitignore new file mode 100644 index 000000000..6f568019d --- /dev/null +++ b/pkgs/jni/example/android/.gitignore @@ -0,0 +1,13 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties +**/*.keystore +**/*.jks diff --git a/pkgs/jni/example/android/app/build.gradle b/pkgs/jni/example/android/app/build.gradle new file mode 100644 index 000000000..fbcc35613 --- /dev/null +++ b/pkgs/jni/example/android/app/build.gradle @@ -0,0 +1,70 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new FileNotFoundException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion flutter.compileSdkVersion + ndkVersion flutter.ndkVersion + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + defaultConfig { + applicationId "com.github.dart_lang.jni_example" + // You can update the following values to match your application needs. + // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration. + minSdkVersion flutter.minSdkVersion + targetSdkVersion flutter.targetSdkVersion + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/pkgs/jni/example/android/app/src/debug/AndroidManifest.xml b/pkgs/jni/example/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 000000000..1a2af73c5 --- /dev/null +++ b/pkgs/jni/example/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,8 @@ + + + + diff --git a/pkgs/jni/example/android/app/src/main/AndroidManifest.xml b/pkgs/jni/example/android/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..5a849fc23 --- /dev/null +++ b/pkgs/jni/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + diff --git a/pkgs/jni/example/android/app/src/main/java/com/github/dart_lang/jni_example/Toaster.java b/pkgs/jni/example/android/app/src/main/java/com/github/dart_lang/jni_example/Toaster.java new file mode 100644 index 000000000..ec61c8ad8 --- /dev/null +++ b/pkgs/jni/example/android/app/src/main/java/com/github/dart_lang/jni_example/Toaster.java @@ -0,0 +1,31 @@ +// 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.jni_example; + +import android.app.Activity; +import android.content.Context; +import android.widget.Toast; +import androidx.annotation.Keep; + +@Keep +class Toaster { + static Toaster makeText(Activity mainActivity, Context context, CharSequence text, int duration) { + Toaster toast = new Toaster(); + toast.mainActivity = mainActivity; + toast.context = context; + toast.text = text; + toast.duration = duration; + return toast; + } + + void show() { + mainActivity.runOnUiThread(() -> Toast.makeText(context, text, duration).show()); + } + + Activity mainActivity; + Context context; + CharSequence text; + int duration; +} diff --git a/pkgs/jni/example/android/app/src/main/kotlin/dev/dart/jni_example/MainActivity.kt b/pkgs/jni/example/android/app/src/main/kotlin/dev/dart/jni_example/MainActivity.kt new file mode 100644 index 000000000..2aa0914b3 --- /dev/null +++ b/pkgs/jni/example/android/app/src/main/kotlin/dev/dart/jni_example/MainActivity.kt @@ -0,0 +1,6 @@ +package com.github.dart_lang.jni_example + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} diff --git a/pkgs/jni/example/android/app/src/main/res/drawable-v21/launch_background.xml b/pkgs/jni/example/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 000000000..f74085f3f --- /dev/null +++ b/pkgs/jni/example/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/pkgs/jni/example/android/app/src/main/res/drawable/launch_background.xml b/pkgs/jni/example/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 000000000..304732f88 --- /dev/null +++ b/pkgs/jni/example/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/pkgs/jni/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/pkgs/jni/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..db77bb4b7 Binary files /dev/null and b/pkgs/jni/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/pkgs/jni/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/pkgs/jni/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..17987b79b Binary files /dev/null and b/pkgs/jni/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/pkgs/jni/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/pkgs/jni/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..09d439148 Binary files /dev/null and b/pkgs/jni/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/pkgs/jni/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/pkgs/jni/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..d5f1c8d34 Binary files /dev/null and b/pkgs/jni/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/pkgs/jni/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/pkgs/jni/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..4d6372eeb Binary files /dev/null and b/pkgs/jni/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/pkgs/jni/example/android/app/src/main/res/values-night/styles.xml b/pkgs/jni/example/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 000000000..06952be74 --- /dev/null +++ b/pkgs/jni/example/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/pkgs/jni/example/android/app/src/main/res/values/styles.xml b/pkgs/jni/example/android/app/src/main/res/values/styles.xml new file mode 100644 index 000000000..cb1ef8805 --- /dev/null +++ b/pkgs/jni/example/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/pkgs/jni/example/android/app/src/profile/AndroidManifest.xml b/pkgs/jni/example/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 000000000..1a2af73c5 --- /dev/null +++ b/pkgs/jni/example/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,8 @@ + + + + diff --git a/pkgs/jni/example/android/build.gradle b/pkgs/jni/example/android/build.gradle new file mode 100644 index 000000000..3cdaac958 --- /dev/null +++ b/pkgs/jni/example/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.6.10' + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:7.1.2' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +tasks.register("clean", Delete) { + delete rootProject.buildDir +} diff --git a/pkgs/jni/example/android/gradle.properties b/pkgs/jni/example/android/gradle.properties new file mode 100644 index 000000000..94adc3a3f --- /dev/null +++ b/pkgs/jni/example/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true diff --git a/pkgs/jni/example/android/gradle/wrapper/gradle-wrapper.properties b/pkgs/jni/example/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..cc5527d78 --- /dev/null +++ b/pkgs/jni/example/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip diff --git a/pkgs/jni/example/android/settings.gradle b/pkgs/jni/example/android/settings.gradle new file mode 100644 index 000000000..44e62bcf0 --- /dev/null +++ b/pkgs/jni/example/android/settings.gradle @@ -0,0 +1,11 @@ +include ':app' + +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() + +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/pkgs/jni/example/integration_test/on_device_jni_test.dart b/pkgs/jni/example/integration_test/on_device_jni_test.dart new file mode 100644 index 000000000..cdc729669 --- /dev/null +++ b/pkgs/jni/example/integration_test/on_device_jni_test.dart @@ -0,0 +1,40 @@ +// 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. + +import 'package:flutter_test/flutter_test.dart'; + +import '../../test/global_env_test.dart' as global_env_test; +import '../../test/exception_test.dart' as exception_test; +import '../../test/jlist_test.dart' as jlist_test; +import '../../test/jmap_test.dart' as jmap_test; +import '../../test/jobject_test.dart' as jobject_test; +import '../../test/jstring_test.dart' as jstring_test; +import '../../test/jset_test.dart' as jset_test; +import '../../test/jarray_test.dart' as jarray_test; +import '../../test/boxed_test.dart' as boxed_test; +import '../../test/type_test.dart' as type_test; +import '../../test/load_test.dart' as load_test; + +void integrationTestRunner(String description, void Function() testCallback) { + testWidgets(description, (widgetTester) async => testCallback()); +} + +void main() { + final testSuites = [ + global_env_test.run, + exception_test.run, + jlist_test.run, + jmap_test.run, + jobject_test.run, + jstring_test.run, + jset_test.run, + jarray_test.run, + boxed_test.run, + type_test.run, + load_test.run, + ]; + for (var testSuite in testSuites) { + testSuite(testRunner: integrationTestRunner); + } +} diff --git a/pkgs/jni/example/lib/main.dart b/pkgs/jni/example/lib/main.dart new file mode 100644 index 000000000..4c73693f3 --- /dev/null +++ b/pkgs/jni/example/lib/main.dart @@ -0,0 +1,224 @@ +// 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. + +// ignore_for_file: library_private_types_in_public_api + +import 'package:flutter/material.dart'; + +import 'dart:io'; +import 'dart:ffi'; + +import 'package:jni/jni.dart'; + +// An example of calling JNI methods using low level primitives. +// GlobalJniEnv is a thin abstraction over JNIEnv in JNI C API. +// +// For a more ergonomic API for common use cases of calling methods and +// accessing fields, see next examples using JObject and JClass. +String toJavaStringUsingEnv(int n) => using((arena) { + final env = Jni.env; + final cls = env.FindClass("java/lang/String".toNativeChars(arena)); + final mId = env.GetStaticMethodID(cls, "valueOf".toNativeChars(), + "(I)Ljava/lang/String;".toNativeChars(arena)); + final i = arena(); + i.ref.i = n; + final res = env.CallStaticObjectMethodA(cls, mId, i); + final str = env.toDartString(res); + env.deleteAllRefs([res, cls]); + return str; + }); + +int randomUsingEnv(int n) => using((arena) { + final env = Jni.env; + final randomCls = env.FindClass("java/util/Random".toNativeChars(arena)); + final ctor = env.GetMethodID( + randomCls, "".toNativeChars(arena), "()V".toNativeChars(arena)); + final random = env.NewObject(randomCls, ctor); + final nextInt = env.GetMethodID(randomCls, "nextInt".toNativeChars(arena), + "(I)I".toNativeChars(arena)); + final res = env.CallIntMethodA(random, nextInt, Jni.jvalues([n])); + env.deleteAllRefs([randomCls, random]); + return res; + }); +double randomDouble() { + final math = Jni.findJClass("java/lang/Math"); + final random = math.callStaticMethodByName("random", "()D", []); + math.release(); + return random; +} + +int uptime() { + return Jni.findJClass("android/os/SystemClock").use( + (systemClock) => systemClock.callStaticMethodByName( + "uptimeMillis", "()J", [], JniCallType.longType), + ); +} + +String backAndForth() { + final jstring = '🪓'.toJString(); + final dartString = jstring.toDartString(releaseOriginal: true); + return dartString; +} + +void quit() { + JObject.fromRef(Jni.getCurrentActivity()) + .use((ac) => ac.callMethodByName("finish", "()V", [])); +} + +void showToast(String text) { + // This is example for calling your app's custom java code. + // Place the Toaster class in the app's android/ source Folder, with a Keep + // annotation or appropriate proguard rules to retain classes in release mode. + // + // In this example, Toaster class wraps android.widget.Toast so that it + // can be called from any thread. See + // android/app/src/main/java/com/github/dart_lang/jni_example/Toaster.java + Jni.invokeStaticMethod( + "com/github/dart_lang/jni_example/Toaster", + "makeText", + "(Landroid/app/Activity;Landroid/content/Context;" + "Ljava/lang/CharSequence;I)" + "Lcom/github/dart_lang/jni_example/Toaster;", + [ + Jni.getCurrentActivity(), + Jni.getCachedApplicationContext(), + "😀", + 0, + ]).callMethodByName("show", "()V", []); +} + +void main() { + if (!Platform.isAndroid) { + Jni.spawn(); + } + final examples = [ + Example("String.valueOf(1332)", () => toJavaStringUsingEnv(1332)), + Example("Generate random number", () => randomUsingEnv(180), + runInitially: false), + Example("Math.random()", () => randomDouble(), runInitially: false), + if (Platform.isAndroid) ...[ + Example("Minutes of usage since reboot", + () => (uptime() / (60 * 1000)).floor()), + Example("Back and forth string conversion", () => backAndForth()), + Example( + "Device name", + () => Jni.retrieveStaticField( + "android/os/Build", "DEVICE", "Ljava/lang/String;")), + Example( + "Package name", + () => JObject.fromRef(Jni.getCurrentActivity()).use((activity) => + activity.callMethodByName( + "getPackageName", "()Ljava/lang/String;", [])), + ), + Example("Show toast", () => showToast("Hello from JNI!"), + runInitially: false), + Example( + "Quit", + quit, + runInitially: false, + ), + ] + ]; + runApp(MyApp(examples)); +} + +class Example { + String title; + dynamic Function() callback; + bool runInitially; + Example(this.title, this.callback, {this.runInitially = true}); +} + +class MyApp extends StatefulWidget { + const MyApp(this.examples, {Key? key}) : super(key: key); + final List examples; + + @override + _MyAppState createState() => _MyAppState(); +} + +class _MyAppState extends State { + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return MaterialApp( + home: Scaffold( + appBar: AppBar( + title: const Text('JNI Examples'), + ), + body: ListView.builder( + itemCount: widget.examples.length, + itemBuilder: (context, i) { + final eg = widget.examples[i]; + return ExampleCard(eg); + }), + ), + ); + } +} + +class ExampleCard extends StatefulWidget { + const ExampleCard(this.example, {Key? key}) : super(key: key); + final Example example; + + @override + _ExampleCardState createState() => _ExampleCardState(); +} + +class _ExampleCardState extends State { + Widget _pad(Widget w, double h, double v) { + return Padding( + padding: EdgeInsets.symmetric(horizontal: h, vertical: v), child: w); + } + + bool _run = false; + + @override + void initState() { + super.initState(); + _run = widget.example.runInitially; + } + + @override + Widget build(BuildContext context) { + final eg = widget.example; + var result = ""; + var hasError = false; + if (_run) { + try { + result = eg.callback().toString(); + } on Exception catch (e) { + hasError = true; + result = e.toString(); + } on Error catch (e) { + hasError = true; + result = e.toString(); + } + } + var resultStyle = const TextStyle(fontFamily: "Monospace"); + if (hasError) { + resultStyle = const TextStyle(fontFamily: "Monospace", color: Colors.red); + } + return Card( + child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ + Text(eg.title, + softWrap: true, + style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600)), + _pad( + Text(result.toString(), softWrap: true, style: resultStyle), 8, 16), + _pad( + ElevatedButton( + child: Text(_run ? "Run again" : "Run"), + onPressed: () => setState(() => _run = true), + ), + 8, + 8), + ]), + ); + } +} diff --git a/pkgs/jni/example/linux/.gitignore b/pkgs/jni/example/linux/.gitignore new file mode 100644 index 000000000..d3896c984 --- /dev/null +++ b/pkgs/jni/example/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/pkgs/jni/example/linux/CMakeLists.txt b/pkgs/jni/example/linux/CMakeLists.txt new file mode 100644 index 000000000..8df6c44ba --- /dev/null +++ b/pkgs/jni/example/linux/CMakeLists.txt @@ -0,0 +1,138 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.10) +project(runner LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "jni_example") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "com.github.dart_lang.jni") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Root filesystem for cross-building. +if(FLUTTER_TARGET_PLATFORM_SYSROOT) + set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +endif() + +# Define build configuration options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Define the application target. To change its name, change BINARY_NAME above, +# not the value here, or `flutter run` will no longer work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# correctly, since the resources must in the right relative locations. To avoid +# people trying to run the unbundled copy, put it in a subdirectory instead of +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/pkgs/jni/example/linux/flutter/CMakeLists.txt b/pkgs/jni/example/linux/flutter/CMakeLists.txt new file mode 100644 index 000000000..d5bd01648 --- /dev/null +++ b/pkgs/jni/example/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/pkgs/jni/example/linux/flutter/generated_plugin_registrant.cc b/pkgs/jni/example/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 000000000..e71a16d23 --- /dev/null +++ b/pkgs/jni/example/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void fl_register_plugins(FlPluginRegistry* registry) { +} diff --git a/pkgs/jni/example/linux/flutter/generated_plugin_registrant.h b/pkgs/jni/example/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 000000000..e0f0a47bc --- /dev/null +++ b/pkgs/jni/example/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/pkgs/jni/example/linux/flutter/generated_plugins.cmake b/pkgs/jni/example/linux/flutter/generated_plugins.cmake new file mode 100644 index 000000000..be1ee3e5b --- /dev/null +++ b/pkgs/jni/example/linux/flutter/generated_plugins.cmake @@ -0,0 +1,24 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST + jni +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/pkgs/jni/example/linux/main.cc b/pkgs/jni/example/linux/main.cc new file mode 100644 index 000000000..e7c5c5437 --- /dev/null +++ b/pkgs/jni/example/linux/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/pkgs/jni/example/linux/my_application.cc b/pkgs/jni/example/linux/my_application.cc new file mode 100644 index 000000000..342054282 --- /dev/null +++ b/pkgs/jni/example/linux/my_application.cc @@ -0,0 +1,104 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // Use a header bar when running in GNOME as this is the common style used + // by applications and is the setup most users will be using (e.g. Ubuntu + // desktop). + // If running on X and not using GNOME then just use a traditional title bar + // in case the window manager does more exotic layout, e.g. tiling. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "jni_example"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "jni_example"); + } + + gtk_window_set_default_size(window, 1280, 720); + gtk_widget_show(GTK_WIDGET(window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, + nullptr)); +} diff --git a/pkgs/jni/example/linux/my_application.h b/pkgs/jni/example/linux/my_application.h new file mode 100644 index 000000000..72271d5e4 --- /dev/null +++ b/pkgs/jni/example/linux/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/pkgs/jni/example/macos/.gitignore b/pkgs/jni/example/macos/.gitignore new file mode 100644 index 000000000..746adbb6b --- /dev/null +++ b/pkgs/jni/example/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/pkgs/jni/example/macos/Flutter/Flutter-Debug.xcconfig b/pkgs/jni/example/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 000000000..4b81f9b2d --- /dev/null +++ b/pkgs/jni/example/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/pkgs/jni/example/macos/Flutter/Flutter-Release.xcconfig b/pkgs/jni/example/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 000000000..5caa9d157 --- /dev/null +++ b/pkgs/jni/example/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/pkgs/jni/example/macos/Flutter/GeneratedPluginRegistrant.swift b/pkgs/jni/example/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 000000000..cccf817a5 --- /dev/null +++ b/pkgs/jni/example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,10 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { +} diff --git a/pkgs/jni/example/macos/Podfile b/pkgs/jni/example/macos/Podfile new file mode 100644 index 000000000..dade8dfad --- /dev/null +++ b/pkgs/jni/example/macos/Podfile @@ -0,0 +1,40 @@ +platform :osx, '10.11' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/pkgs/jni/example/macos/Runner.xcodeproj/project.pbxproj b/pkgs/jni/example/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 000000000..79f7a2099 --- /dev/null +++ b/pkgs/jni/example/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,572 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 51; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* jni_example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "jni_example.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* jni_example.app */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* jni_example.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1300; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/pkgs/jni/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/pkgs/jni/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/pkgs/jni/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/pkgs/jni/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/pkgs/jni/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 000000000..2b12d610f --- /dev/null +++ b/pkgs/jni/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pkgs/jni/example/macos/Runner.xcworkspace/contents.xcworkspacedata b/pkgs/jni/example/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..1d526a16e --- /dev/null +++ b/pkgs/jni/example/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/pkgs/jni/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/pkgs/jni/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/pkgs/jni/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/pkgs/jni/example/macos/Runner/AppDelegate.swift b/pkgs/jni/example/macos/Runner/AppDelegate.swift new file mode 100644 index 000000000..d53ef6437 --- /dev/null +++ b/pkgs/jni/example/macos/Runner/AppDelegate.swift @@ -0,0 +1,9 @@ +import Cocoa +import FlutterMacOS + +@NSApplicationMain +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } +} diff --git a/pkgs/jni/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/pkgs/jni/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..a2ec33f19 --- /dev/null +++ b/pkgs/jni/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/pkgs/jni/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/pkgs/jni/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 000000000..3c4935a7c Binary files /dev/null and b/pkgs/jni/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/pkgs/jni/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/pkgs/jni/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 000000000..ed4cc1642 Binary files /dev/null and b/pkgs/jni/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/pkgs/jni/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/pkgs/jni/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 000000000..483be6138 Binary files /dev/null and b/pkgs/jni/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/pkgs/jni/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/pkgs/jni/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 000000000..bcbf36df2 Binary files /dev/null and b/pkgs/jni/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/pkgs/jni/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/pkgs/jni/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 000000000..9c0a65286 Binary files /dev/null and b/pkgs/jni/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/pkgs/jni/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/pkgs/jni/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 000000000..e71a72613 Binary files /dev/null and b/pkgs/jni/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/pkgs/jni/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/pkgs/jni/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 000000000..8a31fe2dd Binary files /dev/null and b/pkgs/jni/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/pkgs/jni/example/macos/Runner/Base.lproj/MainMenu.xib b/pkgs/jni/example/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 000000000..80e867a4e --- /dev/null +++ b/pkgs/jni/example/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pkgs/jni/example/macos/Runner/Configs/AppInfo.xcconfig b/pkgs/jni/example/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 000000000..acda531a7 --- /dev/null +++ b/pkgs/jni/example/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = jni_example + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.github.dart_lang.jniExample + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2022 com.github.dart_lang. All rights reserved. diff --git a/pkgs/jni/example/macos/Runner/Configs/Debug.xcconfig b/pkgs/jni/example/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 000000000..36b0fd946 --- /dev/null +++ b/pkgs/jni/example/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/pkgs/jni/example/macos/Runner/Configs/Release.xcconfig b/pkgs/jni/example/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 000000000..dff4f4956 --- /dev/null +++ b/pkgs/jni/example/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/pkgs/jni/example/macos/Runner/Configs/Warnings.xcconfig b/pkgs/jni/example/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 000000000..42bcbf478 --- /dev/null +++ b/pkgs/jni/example/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/pkgs/jni/example/macos/Runner/DebugProfile.entitlements b/pkgs/jni/example/macos/Runner/DebugProfile.entitlements new file mode 100644 index 000000000..dddb8a30c --- /dev/null +++ b/pkgs/jni/example/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/pkgs/jni/example/macos/Runner/Info.plist b/pkgs/jni/example/macos/Runner/Info.plist new file mode 100644 index 000000000..4789daa6a --- /dev/null +++ b/pkgs/jni/example/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/pkgs/jni/example/macos/Runner/MainFlutterWindow.swift b/pkgs/jni/example/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 000000000..2722837ec --- /dev/null +++ b/pkgs/jni/example/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController.init() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/pkgs/jni/example/macos/Runner/Release.entitlements b/pkgs/jni/example/macos/Runner/Release.entitlements new file mode 100644 index 000000000..852fa1a47 --- /dev/null +++ b/pkgs/jni/example/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/pkgs/jni/example/pubspec.lock b/pkgs/jni/example/pubspec.lock new file mode 100644 index 000000000..0da0519cb --- /dev/null +++ b/pkgs/jni/example/pubspec.lock @@ -0,0 +1,523 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a + url: "https://pub.dev" + source: hosted + version: "61.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562 + url: "https://pub.dev" + source: hosted + version: "5.13.0" + args: + dependency: transitive + description: + name: args + sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + url: "https://pub.dev" + source: hosted + version: "2.4.2" + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + characters: + dependency: transitive + description: + name: characters + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" + source: hosted + version: "1.1.1" + collection: + dependency: transitive + description: + name: collection + sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 + url: "https://pub.dev" + source: hosted + version: "1.17.2" + convert: + dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + coverage: + dependency: transitive + description: + name: coverage + sha256: "2fb815080e44a09b85e0f2ca8a820b15053982b2e714b59267719e8a9ff17097" + url: "https://pub.dev" + source: hosted + version: "1.6.3" + crypto: + dependency: transitive + description: + name: crypto + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + url: "https://pub.dev" + source: hosted + version: "3.0.3" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be + url: "https://pub.dev" + source: hosted + version: "1.0.5" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + ffi: + dependency: "direct main" + description: + name: ffi + sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + file: + dependency: transitive + description: + name: file + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + url: "https://pub.dev" + source: hosted + version: "6.1.4" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_driver: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + url: "https://pub.dev" + source: hosted + version: "3.2.0" + fuchsia_remote_debug_protocol: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + glob: + dependency: transitive + description: + name: glob + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + integration_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + io: + dependency: transitive + description: + name: io + sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + jni: + dependency: "direct main" + description: + path: ".." + relative: true + source: path + version: "0.6.1" + js: + dependency: transitive + description: + name: js + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.dev" + source: hosted + version: "0.6.7" + lints: + dependency: transitive + description: + name: lints + sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + logging: + dependency: transitive + description: + name: logging + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + url: "https://pub.dev" + source: hosted + version: "0.12.16" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + url: "https://pub.dev" + source: hosted + version: "0.5.0" + meta: + dependency: transitive + description: + name: meta + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + mime: + dependency: transitive + description: + name: mime + sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + url: "https://pub.dev" + source: hosted + version: "1.0.4" + node_preamble: + dependency: transitive + description: + name: node_preamble + sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + package_config: + dependency: transitive + description: + name: package_config + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + path: + dependency: transitive + description: + name: path + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + url: "https://pub.dev" + source: hosted + version: "1.8.3" + platform: + dependency: transitive + description: + name: platform + sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + url: "https://pub.dev" + source: hosted + version: "3.1.0" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "43798d895c929056255600343db8f049921cbec94d31ec87f1dc5c16c01935dd" + url: "https://pub.dev" + source: hosted + version: "2.1.5" + pool: + dependency: transitive + description: + name: pool + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" + source: hosted + version: "1.5.1" + process: + dependency: transitive + description: + name: process + sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" + url: "https://pub.dev" + source: hosted + version: "4.2.4" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + shelf: + dependency: transitive + description: + name: shelf + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + url: "https://pub.dev" + source: hosted + version: "1.4.1" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + shelf_static: + dependency: transitive + description: + name: shelf_static + sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e + url: "https://pub.dev" + source: hosted + version: "1.1.2" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_map_stack_trace: + dependency: transitive + description: + name: source_map_stack_trace + sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + source_maps: + dependency: transitive + description: + name: source_maps + sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" + url: "https://pub.dev" + source: hosted + version: "0.10.12" + source_span: + dependency: transitive + description: + name: source_span + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" + source: hosted + version: "1.10.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" + source: hosted + version: "1.11.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + sync_http: + dependency: transitive + description: + name: sync_http + sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961" + url: "https://pub.dev" + source: hosted + version: "0.3.1" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test: + dependency: "direct dev" + description: + name: test + sha256: "13b41f318e2a5751c3169137103b60c584297353d4b1761b66029bae6411fe46" + url: "https://pub.dev" + source: hosted + version: "1.24.3" + test_api: + dependency: transitive + description: + name: test_api + sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" + url: "https://pub.dev" + source: hosted + version: "0.6.0" + test_core: + dependency: transitive + description: + name: test_core + sha256: "99806e9e6d95c7b059b7a0fc08f07fc53fabe54a829497f0d9676299f1e8637e" + url: "https://pub.dev" + source: hosted + version: "0.5.3" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: c620a6f783fa22436da68e42db7ebbf18b8c44b9a46ab911f666ff09ffd9153f + url: "https://pub.dev" + source: hosted + version: "11.7.1" + watcher: + dependency: transitive + description: + name: watcher + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + web: + dependency: transitive + description: + name: web + sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 + url: "https://pub.dev" + source: hosted + version: "0.1.4-beta" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b + url: "https://pub.dev" + source: hosted + version: "2.4.0" + webdriver: + dependency: transitive + description: + name: webdriver + sha256: "3c923e918918feeb90c4c9fdf1fe39220fa4c0e8e2c0fffaded174498ef86c49" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + sha256: "67d3a8b6c79e1987d19d848b0892e582dbb0c66c57cc1fef58a177dd2aa2823d" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" +sdks: + dart: ">=3.1.0 <4.0.0" + flutter: ">=2.11.0" diff --git a/pkgs/jni/example/pubspec.yaml b/pkgs/jni/example/pubspec.yaml new file mode 100644 index 000000000..ce0646488 --- /dev/null +++ b/pkgs/jni/example/pubspec.yaml @@ -0,0 +1,100 @@ +name: jni_example +description: Demonstrates how to use the jni plugin. + +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +version: 1.0.0+1 + +environment: + sdk: '>=3.1.0 <4.0.0' + +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. +dependencies: + flutter: + sdk: flutter + + ffi: ^2.0.0 + + jni: + # When depending on this package from a real application you should use: + # jni: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. + path: ../ + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.2 + +dev_dependencies: + test: any + flutter_test: + sdk: flutter + integration_test: + sdk: flutter + + # The "flutter_lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # activated in the `analysis_options.yaml` file located at the root of your + # package. See that file for information about deactivating specific lint + # rules and activating additional ones. + flutter_lints: ^2.0.0 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/assets-and-images/#from-packages + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/custom-fonts/#from-packages diff --git a/pkgs/jni/example/windows/.gitignore b/pkgs/jni/example/windows/.gitignore new file mode 100644 index 000000000..d492d0d98 --- /dev/null +++ b/pkgs/jni/example/windows/.gitignore @@ -0,0 +1,17 @@ +flutter/ephemeral/ + +# Visual Studio user-specific files. +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual Studio build-related files. +x64/ +x86/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ diff --git a/pkgs/jni/example/windows/CMakeLists.txt b/pkgs/jni/example/windows/CMakeLists.txt new file mode 100644 index 000000000..19488923e --- /dev/null +++ b/pkgs/jni/example/windows/CMakeLists.txt @@ -0,0 +1,101 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(jni_example LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "jni_example") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Define build configuration option. +get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(IS_MULTICONFIG) + set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" + CACHE STRING "" FORCE) +else() + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") + endif() +endif() +# Define settings for the Profile build mode. +set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") +set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") +set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") +set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") + +# Use Unicode for all projects. +add_definitions(-DUNICODE -D_UNICODE) + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_17) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# Support files are copied into place next to the executable, so that it can +# run in place. This is done instead of making a separate bundle (as on Linux) +# so that building and running from within Visual Studio will work. +set(BUILD_BUNDLE_DIR "$") +# Make the "install" step default, as it's required to run. +set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + CONFIGURATIONS Profile;Release + COMPONENT Runtime) diff --git a/pkgs/jni/example/windows/flutter/CMakeLists.txt b/pkgs/jni/example/windows/flutter/CMakeLists.txt new file mode 100644 index 000000000..930d2071a --- /dev/null +++ b/pkgs/jni/example/windows/flutter/CMakeLists.txt @@ -0,0 +1,104 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.14) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") + +# === Flutter Library === +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "flutter_export.h" + "flutter_windows.h" + "flutter_messenger.h" + "flutter_plugin_registrar.h" + "flutter_texture_registrar.h" +) +list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") +add_dependencies(flutter flutter_assemble) + +# === Wrapper === +list(APPEND CPP_WRAPPER_SOURCES_CORE + "core_implementations.cc" + "standard_codec.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_PLUGIN + "plugin_registrar.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_APP + "flutter_engine.cc" + "flutter_view_controller.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") + +# Wrapper sources needed for a plugin. +add_library(flutter_wrapper_plugin STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} +) +apply_standard_settings(flutter_wrapper_plugin) +set_target_properties(flutter_wrapper_plugin PROPERTIES + POSITION_INDEPENDENT_CODE ON) +set_target_properties(flutter_wrapper_plugin PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) +target_include_directories(flutter_wrapper_plugin PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_plugin flutter_assemble) + +# Wrapper sources needed for the runner. +add_library(flutter_wrapper_app STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_APP} +) +apply_standard_settings(flutter_wrapper_app) +target_link_libraries(flutter_wrapper_app PUBLIC flutter) +target_include_directories(flutter_wrapper_app PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_app flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") +set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} + ${PHONY_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" + windows-x64 $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/pkgs/jni/example/windows/flutter/generated_plugin_registrant.cc b/pkgs/jni/example/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 000000000..8b6d4680a --- /dev/null +++ b/pkgs/jni/example/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void RegisterPlugins(flutter::PluginRegistry* registry) { +} diff --git a/pkgs/jni/example/windows/flutter/generated_plugin_registrant.h b/pkgs/jni/example/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 000000000..dc139d85a --- /dev/null +++ b/pkgs/jni/example/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/pkgs/jni/example/windows/flutter/generated_plugins.cmake b/pkgs/jni/example/windows/flutter/generated_plugins.cmake new file mode 100644 index 000000000..3ad69c612 --- /dev/null +++ b/pkgs/jni/example/windows/flutter/generated_plugins.cmake @@ -0,0 +1,24 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST + jni +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/pkgs/jni/example/windows/runner/CMakeLists.txt b/pkgs/jni/example/windows/runner/CMakeLists.txt new file mode 100644 index 000000000..b9e550fba --- /dev/null +++ b/pkgs/jni/example/windows/runner/CMakeLists.txt @@ -0,0 +1,32 @@ +cmake_minimum_required(VERSION 3.14) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} WIN32 + "flutter_window.cpp" + "main.cpp" + "utils.cpp" + "win32_window.cpp" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" + "Runner.rc" + "runner.exe.manifest" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Disable Windows macros that collide with C++ standard library functions. +target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") + +# Add dependency libraries and include directories. Add any application-specific +# dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/pkgs/jni/example/windows/runner/Runner.rc b/pkgs/jni/example/windows/runner/Runner.rc new file mode 100644 index 000000000..79c3952a8 --- /dev/null +++ b/pkgs/jni/example/windows/runner/Runner.rc @@ -0,0 +1,121 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APP_ICON ICON "resources\\app_icon.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#ifdef FLUTTER_BUILD_NUMBER +#define VERSION_AS_NUMBER FLUTTER_BUILD_NUMBER +#else +#define VERSION_AS_NUMBER 1,0,0 +#endif + +#ifdef FLUTTER_BUILD_NAME +#define VERSION_AS_STRING #FLUTTER_BUILD_NAME +#else +#define VERSION_AS_STRING "1.0.0" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VERSION_AS_NUMBER + PRODUCTVERSION VERSION_AS_NUMBER + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "com.github.dart_lang" "\0" + VALUE "FileDescription", "jni_example" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "jni_example" "\0" + VALUE "LegalCopyright", "Copyright (C) 2022 Dart Project Authors. All rights reserved." "\0" + VALUE "OriginalFilename", "jni_example.exe" "\0" + VALUE "ProductName", "jni_example" "\0" + VALUE "ProductVersion", VERSION_AS_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/pkgs/jni/example/windows/runner/flutter_window.cpp b/pkgs/jni/example/windows/runner/flutter_window.cpp new file mode 100644 index 000000000..b43b9095e --- /dev/null +++ b/pkgs/jni/example/windows/runner/flutter_window.cpp @@ -0,0 +1,61 @@ +#include "flutter_window.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +FlutterWindow::FlutterWindow(const flutter::DartProject& project) + : project_(project) {} + +FlutterWindow::~FlutterWindow() {} + +bool FlutterWindow::OnCreate() { + if (!Win32Window::OnCreate()) { + return false; + } + + RECT frame = GetClientArea(); + + // The size here must match the window dimensions to avoid unnecessary surface + // creation / destruction in the startup path. + flutter_controller_ = std::make_unique( + frame.right - frame.left, frame.bottom - frame.top, project_); + // Ensure that basic setup of the controller was successful. + if (!flutter_controller_->engine() || !flutter_controller_->view()) { + return false; + } + RegisterPlugins(flutter_controller_->engine()); + SetChildContent(flutter_controller_->view()->GetNativeWindow()); + return true; +} + +void FlutterWindow::OnDestroy() { + if (flutter_controller_) { + flutter_controller_ = nullptr; + } + + Win32Window::OnDestroy(); +} + +LRESULT +FlutterWindow::MessageHandler(HWND hwnd, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + // Give Flutter, including plugins, an opportunity to handle window messages. + if (flutter_controller_) { + std::optional result = + flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, + lparam); + if (result) { + return *result; + } + } + + switch (message) { + case WM_FONTCHANGE: + flutter_controller_->engine()->ReloadSystemFonts(); + break; + } + + return Win32Window::MessageHandler(hwnd, message, wparam, lparam); +} diff --git a/pkgs/jni/example/windows/runner/flutter_window.h b/pkgs/jni/example/windows/runner/flutter_window.h new file mode 100644 index 000000000..6da0652f0 --- /dev/null +++ b/pkgs/jni/example/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#include "win32_window.h" + +// A window that does nothing but host a Flutter view. +class FlutterWindow : public Win32Window { + public: + // Creates a new FlutterWindow hosting a Flutter view running |project|. + explicit FlutterWindow(const flutter::DartProject& project); + virtual ~FlutterWindow(); + + protected: + // Win32Window: + bool OnCreate() override; + void OnDestroy() override; + LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, + LPARAM const lparam) noexcept override; + + private: + // The project to run. + flutter::DartProject project_; + + // The Flutter instance hosted by this window. + std::unique_ptr flutter_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/pkgs/jni/example/windows/runner/main.cpp b/pkgs/jni/example/windows/runner/main.cpp new file mode 100644 index 000000000..fa17f9e18 --- /dev/null +++ b/pkgs/jni/example/windows/runner/main.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#include "flutter_window.h" +#include "utils.h" + +int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, + _In_ wchar_t *command_line, _In_ int show_command) { + // Attach to console when present (e.g., 'flutter run') or create a + // new console when running with a debugger. + if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { + CreateAndAttachConsole(); + } + + // Initialize COM, so that it is available for use in the library and/or + // plugins. + ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + + flutter::DartProject project(L"data"); + + std::vector command_line_arguments = + GetCommandLineArguments(); + + project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); + + FlutterWindow window(project); + Win32Window::Point origin(10, 10); + Win32Window::Size size(1280, 720); + if (!window.CreateAndShow(L"jni_example", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/pkgs/jni/example/windows/runner/resource.h b/pkgs/jni/example/windows/runner/resource.h new file mode 100644 index 000000000..66a65d1e4 --- /dev/null +++ b/pkgs/jni/example/windows/runner/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Runner.rc +// +#define IDI_APP_ICON 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/pkgs/jni/example/windows/runner/resources/app_icon.ico b/pkgs/jni/example/windows/runner/resources/app_icon.ico new file mode 100644 index 000000000..c04e20caf Binary files /dev/null and b/pkgs/jni/example/windows/runner/resources/app_icon.ico differ diff --git a/pkgs/jni/example/windows/runner/runner.exe.manifest b/pkgs/jni/example/windows/runner/runner.exe.manifest new file mode 100644 index 000000000..c977c4a42 --- /dev/null +++ b/pkgs/jni/example/windows/runner/runner.exe.manifest @@ -0,0 +1,20 @@ + + + + + PerMonitorV2 + + + + + + + + + + + + + + + diff --git a/pkgs/jni/example/windows/runner/utils.cpp b/pkgs/jni/example/windows/runner/utils.cpp new file mode 100644 index 000000000..f5bf9fa0f --- /dev/null +++ b/pkgs/jni/example/windows/runner/utils.cpp @@ -0,0 +1,64 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +void CreateAndAttachConsole() { + if (::AllocConsole()) { + FILE *unused; + if (freopen_s(&unused, "CONOUT$", "w", stdout)) { + _dup2(_fileno(stdout), 1); + } + if (freopen_s(&unused, "CONOUT$", "w", stderr)) { + _dup2(_fileno(stdout), 2); + } + std::ios::sync_with_stdio(); + FlutterDesktopResyncOutputStreams(); + } +} + +std::vector GetCommandLineArguments() { + // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. + int argc; + wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + if (argv == nullptr) { + return std::vector(); + } + + std::vector command_line_arguments; + + // Skip the first argument as it's the binary name. + for (int i = 1; i < argc; i++) { + command_line_arguments.push_back(Utf8FromUtf16(argv[i])); + } + + ::LocalFree(argv); + + return command_line_arguments; +} + +std::string Utf8FromUtf16(const wchar_t* utf16_string) { + if (utf16_string == nullptr) { + return std::string(); + } + int target_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, nullptr, 0, nullptr, nullptr); + std::string utf8_string; + if (target_length == 0 || target_length > utf8_string.max_size()) { + return utf8_string; + } + utf8_string.resize(target_length); + int converted_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, utf8_string.data(), + target_length, nullptr, nullptr); + if (converted_length == 0) { + return std::string(); + } + return utf8_string; +} diff --git a/pkgs/jni/example/windows/runner/utils.h b/pkgs/jni/example/windows/runner/utils.h new file mode 100644 index 000000000..3879d5475 --- /dev/null +++ b/pkgs/jni/example/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// Creates a console for the process, and redirects stdout and stderr to +// it for both the runner and the Flutter library. +void CreateAndAttachConsole(); + +// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string +// encoded in UTF-8. Returns an empty std::string on failure. +std::string Utf8FromUtf16(const wchar_t* utf16_string); + +// Gets the command line arguments passed in as a std::vector, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/pkgs/jni/example/windows/runner/win32_window.cpp b/pkgs/jni/example/windows/runner/win32_window.cpp new file mode 100644 index 000000000..c10f08dc7 --- /dev/null +++ b/pkgs/jni/example/windows/runner/win32_window.cpp @@ -0,0 +1,245 @@ +#include "win32_window.h" + +#include + +#include "resource.h" + +namespace { + +constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; + +// The number of Win32Window objects that currently exist. +static int g_active_window_count = 0; + +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); + +// Scale helper to convert logical scaler values to physical using passed in +// scale factor +int Scale(int source, double scale_factor) { + return static_cast(source * scale_factor); +} + +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. +// This API is only needed for PerMonitor V1 awareness mode. +void EnableFullDpiSupportIfAvailable(HWND hwnd) { + HMODULE user32_module = LoadLibraryA("User32.dll"); + if (!user32_module) { + return; + } + auto enable_non_client_dpi_scaling = + reinterpret_cast( + GetProcAddress(user32_module, "EnableNonClientDpiScaling")); + if (enable_non_client_dpi_scaling != nullptr) { + enable_non_client_dpi_scaling(hwnd); + FreeLibrary(user32_module); + } +} + +} // namespace + +// Manages the Win32Window's window class registration. +class WindowClassRegistrar { + public: + ~WindowClassRegistrar() = default; + + // Returns the singleton registar instance. + static WindowClassRegistrar* GetInstance() { + if (!instance_) { + instance_ = new WindowClassRegistrar(); + } + return instance_; + } + + // Returns the name of the window class, registering the class if it hasn't + // previously been registered. + const wchar_t* GetWindowClass(); + + // Unregisters the window class. Should only be called if there are no + // instances of the window. + void UnregisterWindowClass(); + + private: + WindowClassRegistrar() = default; + + static WindowClassRegistrar* instance_; + + bool class_registered_ = false; +}; + +WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; + +const wchar_t* WindowClassRegistrar::GetWindowClass() { + if (!class_registered_) { + WNDCLASS window_class{}; + window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); + window_class.lpszClassName = kWindowClassName; + window_class.style = CS_HREDRAW | CS_VREDRAW; + window_class.cbClsExtra = 0; + window_class.cbWndExtra = 0; + window_class.hInstance = GetModuleHandle(nullptr); + window_class.hIcon = + LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); + window_class.hbrBackground = 0; + window_class.lpszMenuName = nullptr; + window_class.lpfnWndProc = Win32Window::WndProc; + RegisterClass(&window_class); + class_registered_ = true; + } + return kWindowClassName; +} + +void WindowClassRegistrar::UnregisterWindowClass() { + UnregisterClass(kWindowClassName, nullptr); + class_registered_ = false; +} + +Win32Window::Win32Window() { + ++g_active_window_count; +} + +Win32Window::~Win32Window() { + --g_active_window_count; + Destroy(); +} + +bool Win32Window::CreateAndShow(const std::wstring& title, + const Point& origin, + const Size& size) { + Destroy(); + + const wchar_t* window_class = + WindowClassRegistrar::GetInstance()->GetWindowClass(); + + const POINT target_point = {static_cast(origin.x), + static_cast(origin.y)}; + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / 96.0; + + HWND window = CreateWindow( + window_class, title.c_str(), WS_OVERLAPPEDWINDOW | WS_VISIBLE, + Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), + Scale(size.width, scale_factor), Scale(size.height, scale_factor), + nullptr, nullptr, GetModuleHandle(nullptr), this); + + if (!window) { + return false; + } + + return OnCreate(); +} + +// static +LRESULT CALLBACK Win32Window::WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + if (message == WM_NCCREATE) { + auto window_struct = reinterpret_cast(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(window_struct->lpCreateParams); + EnableFullDpiSupportIfAvailable(window); + that->window_handle_ = window; + } else if (Win32Window* that = GetThisFromHandle(window)) { + return that->MessageHandler(window, message, wparam, lparam); + } + + return DefWindowProc(window, message, wparam, lparam); +} + +LRESULT +Win32Window::MessageHandler(HWND hwnd, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + switch (message) { + case WM_DESTROY: + window_handle_ = nullptr; + Destroy(); + if (quit_on_close_) { + PostQuitMessage(0); + } + return 0; + + case WM_DPICHANGED: { + auto newRectSize = reinterpret_cast(lparam); + LONG newWidth = newRectSize->right - newRectSize->left; + LONG newHeight = newRectSize->bottom - newRectSize->top; + + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, + newHeight, SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } + case WM_SIZE: { + RECT rect = GetClientArea(); + if (child_content_ != nullptr) { + // Size and position the child window. + MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, TRUE); + } + return 0; + } + + case WM_ACTIVATE: + if (child_content_ != nullptr) { + SetFocus(child_content_); + } + return 0; + } + + return DefWindowProc(window_handle_, message, wparam, lparam); +} + +void Win32Window::Destroy() { + OnDestroy(); + + if (window_handle_) { + DestroyWindow(window_handle_); + window_handle_ = nullptr; + } + if (g_active_window_count == 0) { + WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); + } +} + +Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { + return reinterpret_cast( + GetWindowLongPtr(window, GWLP_USERDATA)); +} + +void Win32Window::SetChildContent(HWND content) { + child_content_ = content; + SetParent(content, window_handle_); + RECT frame = GetClientArea(); + + MoveWindow(content, frame.left, frame.top, frame.right - frame.left, + frame.bottom - frame.top, true); + + SetFocus(child_content_); +} + +RECT Win32Window::GetClientArea() { + RECT frame; + GetClientRect(window_handle_, &frame); + return frame; +} + +HWND Win32Window::GetHandle() { + return window_handle_; +} + +void Win32Window::SetQuitOnClose(bool quit_on_close) { + quit_on_close_ = quit_on_close; +} + +bool Win32Window::OnCreate() { + // No-op; provided for subclasses. + return true; +} + +void Win32Window::OnDestroy() { + // No-op; provided for subclasses. +} diff --git a/pkgs/jni/example/windows/runner/win32_window.h b/pkgs/jni/example/windows/runner/win32_window.h new file mode 100644 index 000000000..17ba43112 --- /dev/null +++ b/pkgs/jni/example/windows/runner/win32_window.h @@ -0,0 +1,98 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// A class abstraction for a high DPI-aware Win32 Window. Intended to be +// inherited from by classes that wish to specialize with custom +// rendering and input handling +class Win32Window { + public: + struct Point { + unsigned int x; + unsigned int y; + Point(unsigned int x, unsigned int y) : x(x), y(y) {} + }; + + struct Size { + unsigned int width; + unsigned int height; + Size(unsigned int width, unsigned int height) + : width(width), height(height) {} + }; + + Win32Window(); + virtual ~Win32Window(); + + // Creates and shows a win32 window with |title| and position and size using + // |origin| and |size|. New windows are created on the default monitor. Window + // sizes are specified to the OS in physical pixels, hence to ensure a + // consistent size to will treat the width height passed in to this function + // as logical pixels and scale to appropriate for the default monitor. Returns + // true if the window was created successfully. + bool CreateAndShow(const std::wstring& title, + const Point& origin, + const Size& size); + + // Release OS resources associated with window. + void Destroy(); + + // Inserts |content| into the window tree. + void SetChildContent(HWND content); + + // Returns the backing Window handle to enable clients to set icon and other + // window properties. Returns nullptr if the window has been destroyed. + HWND GetHandle(); + + // If true, closing this window will quit the application. + void SetQuitOnClose(bool quit_on_close); + + // Return a RECT representing the bounds of the current client area. + RECT GetClientArea(); + + protected: + // Processes and route salient window messages for mouse handling, + // size change and DPI. Delegates handling of these to member overloads that + // inheriting classes can handle. + virtual LRESULT MessageHandler(HWND window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Called when CreateAndShow is called, allowing subclass window-related + // setup. Subclasses should return false if setup fails. + virtual bool OnCreate(); + + // Called when Destroy is called. + virtual void OnDestroy(); + + private: + friend class WindowClassRegistrar; + + // OS callback called by message pump. Handles the WM_NCCREATE message which + // is passed when the non-client area is being created and enables automatic + // non-client DPI scaling so that the non-client area automatically + // responsponds to changes in DPI. All other messages are handled by + // MessageHandler. + static LRESULT CALLBACK WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Retrieves a class instance pointer for |window| + static Win32Window* GetThisFromHandle(HWND const window) noexcept; + + bool quit_on_close_ = false; + + // window handle for top level window. + HWND window_handle_ = nullptr; + + // window handle for hosted content. + HWND child_content_ = nullptr; +}; + +#endif // RUNNER_WIN32_WINDOW_H_ diff --git a/pkgs/jni/ffigen.yaml b/pkgs/jni/ffigen.yaml new file mode 100644 index 000000000..782668e36 --- /dev/null +++ b/pkgs/jni/ffigen.yaml @@ -0,0 +1,157 @@ +# Run with `dart run ffigen --config ffigen.yaml`. +name: JniBindings +description: | + Bindings for libdartjni.so which is part of jni plugin. + + It also transitively includes type definitions such as JNIEnv from third_party/jni.h; + + However, functions prefixed JNI_ are not usable because they are in a different shared library. + + Regenerate bindings with `flutter pub run ffigen.dart --config ffigen.yaml`. +output: 'lib/src/third_party/jni_bindings_generated.dart' +headers: + entry-points: + - 'src/dartjni.h' # Exports majority of JNI functions + - 'src/third_party/global_jni_env.h' # Exports GlobalJniEnv type + - 'src/jni_constants.h' + include-directives: + - 'src/dartjni.h' + - 'src/third_party/global_jni_env.h' + - 'third_party/jni.h' # jni.h from Android NDK + - 'src/jni_constants.h' +compiler-opts: + - '-Ithird_party/' +enums: + rename: + 'JniType': 'JniCallType' + 'jobjectRefType': 'JObjectRefType' +functions: + exclude: + # Exclude init functions supposed to be defined in loaded DLL, not JNI + - 'JNI_.*' + - 'GetJniContextPtr' + - 'setJniGetters' + - 'jni_log' + # Inline functions + # keep-sorted start + - 'acquire_lock' + - 'attach_thread' + - 'check_exception' + - 'destroy_cond' + - 'destroy_lock' + - 'init_cond' + - 'init_lock' + - 'load_class' + - 'load_class_global_ref' + - 'load_class_local_ref' + - 'load_class_platform' + - 'load_env' + - 'load_field' + - 'load_method' + - 'load_static_field' + - 'load_static_method' + - 'release_lock' + - 'signal_cond' + - 'thread_id' + - 'to_global_ref' + - 'to_global_ref_result' + - 'wait_for' + # keep-sorted end +structs: + exclude: + - 'JniContext' + - 'JniLocks' + - 'JNIEnv' + - '_JNIEnv' + - 'JNIInvokeInterface' + - '__va_list_tag' + - 'CallbackResult' + rename: + ## opaque struct definitions, base types of jfieldID and jmethodID + '_jfieldID': 'jfieldID_' + '_jmethodID': + 'jmethodID_' + #'JNI(.*)': 'Jni$1' +unions: + rename: + 'jvalue': 'JValue' +globals: + exclude: + - 'jni' + - 'jniEnv' + - 'context_getter' + - 'env_getter' +typedefs: + exclude: + - 'va_list' + - '__builtin_va_list' + rename: + 'JNI(.*)': 'Jni$1' + # Primitives + 'jbyte': 'JByteMarker' + 'jboolean': 'JBooleanMarker' + 'jchar': 'JCharMarker' + 'jshort': 'JShortMarker' + 'jint': 'JIntMarker' + 'jlong': 'JLongMarker' + 'jfloat': 'JFloatMarker' + 'jdouble': 'JDoubleMarker' + 'jsize': 'JSizeMarker' + + 'jclass': 'JClassPtr' + 'jobject': 'JObjectPtr' + 'jmethodID': 'JMethodIDPtr' + 'jfieldID': 'JFieldIDPtr' + 'jthrowable': 'JThrowablePtr' + 'jstring': 'JStringPtr' + 'jarray': 'JArrayPtr' + 'jobjectArray': 'JObjectArrayPtr' + 'jbooleanArray': 'JBooleanArrayPtr' + 'jbyteArray': 'JByteArrayPtr' + 'jcharArray': 'JCharArrayPtr' + 'jshortArray': 'JShortArrayPtr' + 'jintArray': 'JIntArrayPtr' + 'jlongArray': 'JLongArrayPtr' + 'jfloatArray': 'JFloatArrayPtr' + 'jdoubleArray': 'JDoubleArrayPtr' + 'jweak': 'JWeakPtr' + 'jvalue': 'JValue' +preamble: | + // Autogenerated file. Do not edit. + // Generated from an annotated version of jni.h provided in Android NDK. + // (NDK Version 23.1.7779620) + // The license for original file is provided below: + + /* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /* + * JNI specification, as defined by Sun: + * http://java.sun.com/javase/6/docs/technotes/guides/jni/spec/jniTOC.html + * + * Everything here is expected to be VM-neutral. + */ + + // ignore_for_file: always_specify_types + // ignore_for_file: camel_case_types + // ignore_for_file: non_constant_identifier_names + // ignore_for_file: constant_identifier_names + // ignore_for_file: unused_field + // ignore_for_file: unused_element + // coverage:ignore-file +comments: + style: any + length: full diff --git a/pkgs/jni/ffigen_exts.yaml b/pkgs/jni/ffigen_exts.yaml new file mode 100644 index 000000000..d292ad63a --- /dev/null +++ b/pkgs/jni/ffigen_exts.yaml @@ -0,0 +1,16 @@ +# Run with `dart run ffigen --config ffigen.yaml`. +name: JniExtensions +description: | + This config is for use by the script that generates extension methods in C. + This config only scans jni.h and does not do renaming etc.. +output: 'unused.dart' +headers: + entry-points: + - 'third_party/jni.h' # Exports majority of JNI functions + #- 'src/third_party/global_jni_env.h' # Exports GlobalJniEnv type + include-directives: + #- 'src/dartjni.h' + #- 'src/third_party/global_jni_env.h' + - 'third_party/jni.h' # jni.h from Android NDK +compiler-opts: + - '-Ithird_party/' diff --git a/pkgs/jni/java/.gitignore b/pkgs/jni/java/.gitignore new file mode 100644 index 000000000..9f970225a --- /dev/null +++ b/pkgs/jni/java/.gitignore @@ -0,0 +1 @@ +target/ \ No newline at end of file diff --git a/pkgs/jni/java/README.md b/pkgs/jni/java/README.md new file mode 100644 index 000000000..18a6cd38c --- /dev/null +++ b/pkgs/jni/java/README.md @@ -0,0 +1,4 @@ +# Jni Java + +This is a standalone java support which includes `PortContinuation` to support +converting from Kotlin's `suspend fun` to Dart's `async` functions. diff --git a/pkgs/jni/java/pom.xml b/pkgs/jni/java/pom.xml new file mode 100644 index 000000000..2bd6f88d4 --- /dev/null +++ b/pkgs/jni/java/pom.xml @@ -0,0 +1,35 @@ + + + 4.0.0 + + org.example + java + 1.0-SNAPSHOT + + + 11 + 11 + UTF-8 + + + + jni + ${target} + + + + + org.jetbrains.kotlin + kotlin-stdlib + 1.6.20 + + + org.jetbrains.kotlinx + kotlinx-coroutines-core + 1.6.4 + pom + + + \ No newline at end of file diff --git a/pkgs/jni/java/src/main/java/com/github/dart_lang/jni/PortCleaner.java b/pkgs/jni/java/src/main/java/com/github/dart_lang/jni/PortCleaner.java new file mode 100644 index 000000000..161ef5ea5 --- /dev/null +++ b/pkgs/jni/java/src/main/java/com/github/dart_lang/jni/PortCleaner.java @@ -0,0 +1,88 @@ +// Copyright (c) 2023, 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.jni; + +import java.lang.ref.PhantomReference; +import java.lang.ref.ReferenceQueue; + +/// A registry of Java objects with associated Dart resources that cleans up the +/// resources after they get unreachable and collected by the garbage collector. +/// +/// A simple alternative to [java.lang.ref.Cleaner] which is only available in +/// Android API level 33+. +class PortCleaner { + static { + System.loadLibrary("dartjni"); + } + + private final ReferenceQueue queue = new ReferenceQueue<>(); + private final PortPhantom list = new PortPhantom(); + + private class PortPhantom extends PhantomReference { + final long port; + + /// Form a linked list. + PortPhantom prev = this, next = this; + + PortPhantom(Object referent, long port) { + super(referent, queue); + this.port = port; + insert(); + } + + /// Only used for the head of the list. + PortPhantom() { + super(null, null); + this.port = 0; + } + + void insert() { + synchronized (list) { + prev = list; + next = list.next; + next.prev = this; + list.next = this; + } + } + + private void remove() { + synchronized (list) { + next.prev = prev; + prev.next = next; + prev = this; + next = this; + } + } + } + + PortCleaner() { + // Only a single PortCleaner and therefore thread will be created. + Thread thread = + new Thread( + () -> { + while (true) { + try { + PortPhantom portPhantom = (PortPhantom) queue.remove(); + portPhantom.remove(); + if (portPhantom.port != 0) { + clean(portPhantom.port); + } + } catch (Throwable e) { + // Ignore. + } + } + }, + "PortCleaner"); + thread.setDaemon(true); + thread.start(); + } + + /// Registers [obj] to be cleaned up later by sending a signal through [port]. + void register(Object obj, long port) { + new PortPhantom(obj, port); + } + + private static native void clean(long port); +} diff --git a/pkgs/jni/java/src/main/java/com/github/dart_lang/jni/PortContinuation.java b/pkgs/jni/java/src/main/java/com/github/dart_lang/jni/PortContinuation.java new file mode 100644 index 000000000..2900ab128 --- /dev/null +++ b/pkgs/jni/java/src/main/java/com/github/dart_lang/jni/PortContinuation.java @@ -0,0 +1,38 @@ +// Copyright (c) 2023, 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.jni; + +import kotlin.coroutines.Continuation; +import kotlin.coroutines.CoroutineContext; +import kotlinx.coroutines.Dispatchers; + +/// An implementation of kotlin.coroutines.Continuation which sends the address +/// of the object to Dart through a native port. +/// +/// This allows converting Kotlin coroutines to Dart async methods. +/// The implementation of native void _resumeWith is located in `dartjni.c`. +public class PortContinuation implements Continuation { + static { + System.loadLibrary("dartjni"); + } + + private final long port; + + public PortContinuation(long port) { + this.port = port; + } + + @Override + public CoroutineContext getContext() { + return (CoroutineContext) Dispatchers.getIO(); + } + + @Override + public void resumeWith(Object o) { + _resumeWith(port, o); + } + + private native void _resumeWith(long port, Object result); +} diff --git a/pkgs/jni/java/src/main/java/com/github/dart_lang/jni/PortProxy.java b/pkgs/jni/java/src/main/java/com/github/dart_lang/jni/PortProxy.java new file mode 100644 index 000000000..3caf02af1 --- /dev/null +++ b/pkgs/jni/java/src/main/java/com/github/dart_lang/jni/PortProxy.java @@ -0,0 +1,104 @@ +// Copyright (c) 2023, 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.jni; + +import java.lang.reflect.*; + +public class PortProxy implements InvocationHandler { + static { + System.loadLibrary("dartjni"); + } + + private static final PortCleaner cleaner = new PortCleaner(); + private final long port; + private final long isolateId; + private final long functionPtr; + + private PortProxy(long port, long isolateId, long functionPtr) { + this.port = port; + this.isolateId = isolateId; + this.functionPtr = functionPtr; + } + + private static String getDescriptor(Method method) { + StringBuilder descriptor = new StringBuilder(); + descriptor.append(method.getName()).append('('); + Class[] parameterTypes = method.getParameterTypes(); + for (Class paramType : parameterTypes) { + appendType(descriptor, paramType); + } + descriptor.append(')'); + appendType(descriptor, method.getReturnType()); + return descriptor.toString(); + } + + private static void appendType(StringBuilder descriptor, Class type) { + if (type == void.class) { + descriptor.append('V'); + } else if (type == boolean.class) { + descriptor.append('Z'); + } else if (type == byte.class) { + descriptor.append('B'); + } else if (type == char.class) { + descriptor.append('C'); + } else if (type == short.class) { + descriptor.append('S'); + } else if (type == int.class) { + descriptor.append('I'); + } else if (type == long.class) { + descriptor.append('J'); + } else if (type == float.class) { + descriptor.append('F'); + } else if (type == double.class) { + descriptor.append('D'); + } else if (type.isArray()) { + descriptor.append('['); + appendType(descriptor, type.getComponentType()); + } else { + descriptor.append('L').append(type.getName().replace('.', '/')).append(';'); + } + } + + public static Object newInstance(String binaryName, long port, long isolateId, long functionPtr) + throws ClassNotFoundException { + Class clazz = Class.forName(binaryName); + Object obj = + Proxy.newProxyInstance( + clazz.getClassLoader(), + new Class[] {clazz}, + new PortProxy(port, isolateId, functionPtr)); + cleaner.register(obj, port); + return obj; + } + + private static final class DartException extends Exception { + private DartException(String message) { + super(message); + } + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws DartException { + Object[] result = _invoke(port, isolateId, functionPtr, proxy, getDescriptor(method), args); + _cleanUp((Long) result[0]); + if (result[1] instanceof DartException) { + throw (DartException) result[1]; + } + return result[1]; + } + + /// Returns an array with two objects: + /// [0]: The address of the result pointer used for the clean-up. + /// [1]: The result of the invocation. + private static native Object[] _invoke( + long port, + long isolateId, + long functionPtr, + Object proxy, + String methodDescriptor, + Object[] args); + + private static native void _cleanUp(long resultPtr); +} diff --git a/pkgs/jni/lib/internal_helpers_for_jnigen.dart b/pkgs/jni/lib/internal_helpers_for_jnigen.dart new file mode 100644 index 000000000..257b0c25d --- /dev/null +++ b/pkgs/jni/lib/internal_helpers_for_jnigen.dart @@ -0,0 +1,12 @@ +// 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. + +/// This library exports the methods meant for use by generated code only, and +/// not to be used directly. +library internal_helpers_for_jnigen; + +export 'src/accessors.dart'; +export 'src/jni.dart' show ProtectedJniExtensions; +export 'src/jreference.dart'; +export 'src/method_invocation.dart'; diff --git a/pkgs/jni/lib/jni.dart b/pkgs/jni/lib/jni.dart new file mode 100644 index 000000000..5f0f34cdb --- /dev/null +++ b/pkgs/jni/lib/jni.dart @@ -0,0 +1,79 @@ +// 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 jni provides dart bindings for the Java Native Interface (JNI) on +/// Android and desktop platforms. +/// +/// It's intended as a supplement to the jnigen tool, a Java wrapper generator +/// using JNI. The goal of this package is to provide sufficiently complete +/// and ergonomic access to underlying JNI APIs. +/// +/// Therefore, some understanding of JNI is required to use this module. +/// +/// ## Java VM +/// On Android, the existing JVM is used, a new JVM needs to be spawned on +/// flutter desktop & standalone targets. +/// +/// ```dart +/// if (!Platform.isAndroid) { +/// // Spin up a JVM instance with custom classpath etc.. +/// Jni.spawn(/* options */); +/// } +/// ``` +/// +/// ## Dart standalone support +/// On dart standalone target, we unfortunately have no mechanism to bundle +/// the wrapper libraries with the executable. Thus it needs to be explicitly +/// placed in a accessible directory and provided as an argument to Jni.spawn. +/// +/// This module depends on a shared library written in C. Therefore on dart +/// standalone: +/// +/// * Run `dart run jni:setup` to build the shared library. This command builds +/// all dependency libraries with native code (package:jni and jnigen-generated) +/// libraries if any. +/// +/// The default output directory is build/jni_libs, which can be changed +/// using `-B` switch. +/// +/// * Provide the location of library to `Jni.spawn` call. +/// +/// ## JNIEnv +/// `GlobalJniEnv` type provides a thin wrapper over `JNIEnv*` which can be used +/// from across threads, and always returns JNI global references. This is +/// needed because Dart doesn't make guarantees about even the straight-line +/// code being scheduled on the same thread. +/// +/// ## Debugging +/// Debugging JNI errors hard in general. +/// +/// * On desktop platforms you can use JniEnv.ExceptionDescribe to print any +/// pending exception to stdout. +/// * On Android, things are slightly easier since CheckJNI is usually enabled +/// in debug builds. If you are not getting clear stack traces on JNI errors, +/// check the Android NDK page on how to enable CheckJNI using ADB. +/// * As a rule of thumb, when there's a NoClassDefFound / NoMethodFound error, +/// first check your class and method signatures for typos. Another common +/// reason for NoClassDefFound error is missing classes in classpath. + +/// This library provides classes and functions for JNI interop from Dart. +library jni; + +export 'src/errors.dart'; +export 'src/jni.dart' hide ProtectedJniExtensions; +export 'src/jvalues.dart' hide JValueArgs, toJValues; +export 'src/types.dart'; +export 'src/jarray.dart'; +export 'src/jobject.dart'; +export 'src/jreference.dart' show JReferenceUseExtension; + +export 'src/lang/lang.dart'; +export 'src/nio/nio.dart'; +export 'src/util/util.dart'; + +export 'src/third_party/generated_bindings.dart' + hide JniBindings, JniEnv, JniEnv1, JniExceptionDetails; + +export 'package:ffi/ffi.dart' show using, Arena; +export 'dart:ffi' show nullptr; diff --git a/pkgs/jni/lib/jni_symbols.yaml b/pkgs/jni/lib/jni_symbols.yaml new file mode 100644 index 000000000..ac4a74c0c --- /dev/null +++ b/pkgs/jni/lib/jni_symbols.yaml @@ -0,0 +1,85 @@ +version: 1.0.0 +files: + 'jni.dart': + 'java.lang.Object': + name: JObject + type_class: JObjectType + super_count: 0 + 'java.lang.String': + name: JString + type_class: JStringType + super_count: 1 + 'java.lang.Number': + name: JNumber + type_class: JNumberType + super_count: 1 + 'java.lang.Byte': + name: JByte + type_class: JByteType + super_count: 2 + 'java.lang.Short': + name: JShort + type_class: JShortType + super_count: 2 + 'java.lang.Integer': + name: JInteger + type_class: JIntegerType + super_count: 2 + 'java.lang.Long': + name: JLong + type_class: JLongType + super_count: 2 + 'java.lang.Float': + name: JFloat + type_class: JFloatType + super_count: 2 + 'java.lang.Double': + name: JDouble + type_class: JDoubleType + super_count: 2 + 'java.lang.Boolean': + name: JBoolean + type_class: JBooleanType + super_count: 1 + 'java.lang.Character': + name: JCharacter + type_class: JCharacterType + super_count: 1 + 'java.util.Set': + name: JSet + type_class: JSetType + super_count: 1 + type_params: + E: + 'java.lang.Object': DECLARED + 'java.util.List': + name: JList + type_class: JListType + super_count: 1 + type_params: + E: + 'java.lang.Object': DECLARED + 'java.util.Iterator': + name: JIterator + type_class: JIteratorType + super_count: 1 + type_params: + E: + 'java.lang.Object': DECLARED + 'java.util.Map': + name: JMap + type_class: JMapType + super_count: 1 + type_params: + K: + 'java.lang.Object': DECLARED + V: + 'java.lang.Object': DECLARED + 'java.nio.Buffer': + name: JBuffer + type_class: JBufferType + super_count: 1 + 'java.nio.ByteBuffer': + name: JByteBuffer + type_class: JByteBufferType + super_count: 2 diff --git a/pkgs/jni/lib/src/accessors.dart b/pkgs/jni/lib/src/accessors.dart new file mode 100644 index 000000000..e505b9470 --- /dev/null +++ b/pkgs/jni/lib/src/accessors.dart @@ -0,0 +1,162 @@ +// 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. + +import 'dart:ffi'; +import 'package:ffi/ffi.dart' show using; + +import 'package:jni/src/jvalues.dart'; + +import 'errors.dart'; +import 'third_party/generated_bindings.dart'; +import 'jni.dart'; + +void _check(JThrowablePtr exception) { + if (exception != nullptr) { + Jni.accessors.throwException(exception); + } +} + +extension JniResultMethods on JniResult { + void check() => _check(exception); + + int get byte { + check(); + return value.b; + } + + int get short { + check(); + return value.s; + } + + int get char { + check(); + return value.c; + } + + int get integer { + check(); + return value.i; + } + + int get long { + check(); + return value.j; + } + + double get float { + check(); + return value.f; + } + + double get doubleFloat { + check(); + return value.d; + } + + JObjectPtr get object { + check(); + return value.l; + } + + bool get boolean { + check(); + return value.z != 0; + } +} + +extension JniIdLookupResultMethods on JniPointerResult { + JMethodIDPtr get methodID { + _check(exception); + return value.cast(); + } + + JFieldIDPtr get fieldID { + _check(exception); + return value.cast(); + } + + Pointer get checkedRef { + _check(exception); + return value; + } + + Pointer getPointer() { + return value.cast(); + } +} + +extension JniClassLookupResultMethods on JniClassLookupResult { + JClassPtr get checkedClassRef { + _check(exception); + return value; + } +} + +extension JThrowableCheckMethod on JThrowablePtr { + void check() { + _check(this); + } +} + +extension JniAccessorWrappers on JniAccessors { + /// Rethrows Java exception in Dart as [JniException]. + /// + /// The original exception object is deleted by this method. The message + /// and Java stack trace are included in the exception. + void throwException(JThrowablePtr exception) { + final details = getExceptionDetails(exception); + final env = Jni.env; + final message = env.toDartString(details.message); + final stacktrace = env.toDartString(details.stacktrace); + env.DeleteGlobalRef(exception); + env.DeleteGlobalRef(details.message); + env.DeleteGlobalRef(details.stacktrace); + throw JniException(message, stacktrace); + } + + // TODO(PR): How to name these methods? These only wrap toNativeChars() + // so that generated bindings are less verbose. + JClassPtr getClassOf(String internalName) => + using((arena) => getClass(internalName.toNativeChars(arena))) + .checkedClassRef; + + JMethodIDPtr getMethodIDOf(JClassPtr cls, String name, String signature) => + using((arena) => getMethodID( + cls, name.toNativeChars(arena), signature.toNativeChars(arena))) + .methodID; + + JMethodIDPtr getStaticMethodIDOf( + JClassPtr cls, String name, String signature) => + using((arena) => getStaticMethodID( + cls, name.toNativeChars(arena), signature.toNativeChars(arena))) + .methodID; + + JFieldIDPtr getFieldIDOf(JClassPtr cls, String name, String signature) => + using((arena) => getFieldID( + cls, name.toNativeChars(arena), signature.toNativeChars(arena))) + .fieldID; + + JFieldIDPtr getStaticFieldIDOf( + JClassPtr cls, String name, String signature) => + using((arena) => getStaticFieldID( + cls, name.toNativeChars(arena), signature.toNativeChars(arena))) + .fieldID; + + JniResult newObjectWithArgs( + JClassPtr cls, JMethodIDPtr ctor, List args) => + using((arena) { + return newObject(cls, ctor, toJValues(args, allocator: arena)); + }); + + JniResult callMethodWithArgs( + JObjectPtr obj, JMethodIDPtr id, int callType, List args) => + using((arena) => + callMethod(obj, id, callType, toJValues(args, allocator: arena))); + + JniResult callStaticMethodWithArgs( + JClassPtr cls, JMethodIDPtr id, int callType, List args) => + using((arena) => callStaticMethod( + cls, id, callType, toJValues(args, allocator: arena))); +} diff --git a/pkgs/jni/lib/src/build_util/build_util.dart b/pkgs/jni/lib/src/build_util/build_util.dart new file mode 100644 index 000000000..8d267dfa3 --- /dev/null +++ b/pkgs/jni/lib/src/build_util/build_util.dart @@ -0,0 +1,24 @@ +// 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. + +// Any shared build logic should be here. This way it can be reused across bin/, +// tool/ and test/. + +import 'dart:io'; + +const ansiRed = '\x1b[31m'; +const ansiDefault = '\x1b[39;49m'; + +/// Returns true if [artifact] does not exist, or any file in [sourceDir] is +/// newer than [artifact]. +bool needsBuild(File artifact, Directory sourceDir) { + if (!artifact.existsSync()) return true; + final fileLastModified = artifact.lastModifiedSync(); + for (final entry in sourceDir.listSync(recursive: true)) { + if (entry.statSync().modified.isAfter(fileLastModified)) { + return true; + } + } + return false; +} diff --git a/pkgs/jni/lib/src/errors.dart b/pkgs/jni/lib/src/errors.dart new file mode 100644 index 000000000..848d93eaa --- /dev/null +++ b/pkgs/jni/lib/src/errors.dart @@ -0,0 +1,144 @@ +// Copyright (c) 2023, 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. + +import 'package:jni/src/third_party/generated_bindings.dart'; + +// TODO(#393): Add the fact that [JException] is now a [JObject] to the +// CHANGELOG. + +final class UseAfterReleaseError extends Error { + @override + String toString() { + return 'Use after release error'; + } +} + +// TODO(#393): Use NullPointerError once it's available. +final class JNullError extends Error { + @override + String toString() => 'The reference was null'; +} + +final class DoubleReleaseError extends Error { + @override + String toString() { + return 'Double release error'; + } +} + +/// Represents JNI errors that might be returned by methods like +/// `JNI_CreateJavaVM`. +sealed class JniError extends Error { + static const _errors = { + JniErrorCode.JNI_ERR: JniGenericError.new, + JniErrorCode.JNI_EDETACHED: JniThreadDetachedError.new, + JniErrorCode.JNI_EVERSION: JniVersionError.new, + JniErrorCode.JNI_ENOMEM: JniOutOfMemoryError.new, + JniErrorCode.JNI_EEXIST: JniVmExistsError.new, + JniErrorCode.JNI_EINVAL: JniArgumentError.new, + }; + + final String message; + + JniError(this.message); + + factory JniError.of(int status) { + if (!_errors.containsKey(status)) { + status = JniErrorCode.JNI_ERR; + } + return _errors[status]!(); + } + + @override + String toString() { + return 'JniError: $message'; + } +} + +final class JniGenericError extends JniError { + JniGenericError() : super('Generic JNI error'); +} + +final class JniThreadDetachedError extends JniError { + JniThreadDetachedError() : super('Thread detached from VM'); +} + +final class JniVersionError extends JniError { + JniVersionError() : super('JNI version error'); +} + +final class JniOutOfMemoryError extends JniError { + JniOutOfMemoryError() : super('Out of memory'); +} + +final class JniVmExistsError extends JniError { + JniVmExistsError() : super('VM Already created'); +} + +final class JniArgumentError extends JniError { + JniArgumentError() : super('Invalid arguments'); +} + +final class NoJvmInstanceError extends Error { + @override + String toString() => 'No JNI instance is available'; +} + +// TODO(#395): Remove this when calltypes are removed. +extension on int { + static const _names = { + JniCallType.booleanType: 'bool', + JniCallType.byteType: 'byte', + JniCallType.shortType: 'short', + JniCallType.charType: 'char', + JniCallType.intType: 'int', + JniCallType.longType: 'long', + JniCallType.floatType: 'float', + JniCallType.doubleType: 'double', + JniCallType.objectType: 'object', + JniCallType.voidType: 'void', + }; + String str() => _names[this]!; +} + +// TODO(#395): Remove this when `JniCallType`s are removed. +final class InvalidCallTypeError extends Error { + final int type; + final Set allowed; + + InvalidCallTypeError(this.type, this.allowed); + + @override + String toString() => 'Invalid type for call ${type.str()}. ' + 'Allowed types are ${allowed.map((t) => t.str()).toSet()}'; +} + +// TODO(#393): Remove this class in favor of `JThrowable`. +class JniException implements Exception { + /// Error message from Java exception. + final String message; + + /// Stack trace from Java. + final String stackTrace; + + JniException(this.message, this.stackTrace); + + @override + String toString() => 'Exception in Java code called through JNI: ' + '$message\n\n$stackTrace\n'; +} + +final class HelperNotFoundError extends Error { + final String path; + + HelperNotFoundError(this.path); + + @override + String toString() => ''' +Lookup for helper library $path failed. +Please ensure that `dartjni` shared library is built. +Provided jni:setup script can be used to build the shared library. +If the library is already built, ensure that the JVM libraries can be +loaded from Dart.'''; +} diff --git a/pkgs/jni/lib/src/jarray.dart b/pkgs/jni/lib/src/jarray.dart new file mode 100644 index 000000000..23643127c --- /dev/null +++ b/pkgs/jni/lib/src/jarray.dart @@ -0,0 +1,369 @@ +// 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. + +// ignore_for_file: unnecessary_cast, overridden_fields + +import 'dart:ffi'; + +import 'package:collection/collection.dart'; +import 'package:ffi/ffi.dart'; +import 'package:jni/src/accessors.dart'; +import 'package:jni/src/third_party/generated_bindings.dart'; + +import 'jni.dart'; +import 'jobject.dart'; +import 'types.dart'; + +final class JArrayType extends JObjType> { + final JType elementType; + + const JArrayType(this.elementType); + + @override + String get signature => '[${elementType.signature}'; + + @override + JArray fromRef(Pointer ref) => JArray.fromRef(elementType, ref); + + @override + JObjType get superType => const JObjectType(); + + @override + final int superCount = 1; + + @override + int get hashCode => Object.hash(JArrayType, elementType); + + @override + bool operator ==(Object other) { + return other.runtimeType == (JArrayType) && + other is JArrayType && + elementType == other.elementType; + } +} + +class JArray extends JObject { + final JType elementType; + + @override + late final JArrayType $type = type(elementType) as JArrayType; + + /// The type which includes information such as the signature of this class. + static JObjType> type(JType innerType) => + JArrayType(innerType); + + /// Construct a new [JArray] with [reference] as its underlying reference. + JArray.fromRef(this.elementType, JArrayPtr reference) + : super.fromRef(reference); + + /// Creates a [JArray] of the given length from the given [type]. + /// + /// The [length] must be a non-negative integer. + factory JArray(JType type, int length) { + const primitiveCallTypes = { + 'B': JniCallType.byteType, + 'Z': JniCallType.booleanType, + 'C': JniCallType.charType, + 'S': JniCallType.shortType, + 'I': JniCallType.intType, + 'J': JniCallType.longType, + 'F': JniCallType.floatType, + 'D': JniCallType.doubleType, + }; + if (!primitiveCallTypes.containsKey(type.signature) && type is JObjType) { + final clazz = (type as JObjType).getClass(); + final array = JArray.fromRef( + type, + Jni.accessors.newObjectArray(length, clazz.reference, nullptr).object, + ); + clazz.release(); + return array; + } + return JArray.fromRef( + type, + Jni.accessors + .newPrimitiveArray(length, primitiveCallTypes[type.signature]!) + .object, + ); + } + + /// Creates a [JArray] of the given length with [fill] at each position. + /// + /// The [length] must be a non-negative integer. + static JArray filled(int length, E fill) { + RangeError.checkNotNegative(length); + final clazz = fill.$type.getClass(); + final array = JArray.fromRef( + fill.$type as JObjType, + Jni.accessors + .newObjectArray(length, clazz.reference, fill.reference) + .object, + ); + clazz.release(); + return array; + } + + int? _length; + + JniResult elementAt(int index, int type) { + RangeError.checkValidIndex(index, this); + return Jni.accessors.getArrayElement(reference, index, type); + } + + /// The number of elements in this array. + int get length { + return _length ??= Jni.env.GetArrayLength(reference); + } +} + +extension NativeArray on JArray { + void _allocate( + int size, + void Function(Pointer ptr) use, + ) { + using((arena) { + final ptr = arena.allocate(size); + use(ptr); + }, malloc); + } +} + +extension BoolArray on JArray { + bool operator [](int index) { + return elementAt(index, JniCallType.booleanType).boolean; + } + + void operator []=(int index, bool value) { + RangeError.checkValidIndex(index, this); + _allocate(sizeOf(), (ptr) { + ptr.value = value ? 1 : 0; + Jni.env.SetBooleanArrayRegion(reference, index, 1, ptr); + }); + } + + void setRange(int start, int end, Iterable iterable, + [int skipCount = 0]) { + RangeError.checkValidRange(start, end, length); + final size = end - start; + final it = iterable.skip(skipCount).take(size); + _allocate(sizeOf() * size, (ptr) { + it.forEachIndexed((index, element) { + ptr[index] = element ? 1 : 0; + }); + Jni.env.SetBooleanArrayRegion(reference, start, size, ptr); + }); + } +} + +extension ByteArray on JArray { + int operator [](int index) { + return elementAt(index, JniCallType.byteType).byte; + } + + void operator []=(int index, int value) { + RangeError.checkValidIndex(index, this); + _allocate(sizeOf(), (ptr) { + ptr.value = value; + Jni.env.SetByteArrayRegion(reference, index, 1, ptr); + }); + } + + void setRange(int start, int end, Iterable iterable, + [int skipCount = 0]) { + RangeError.checkValidRange(start, end, length); + final size = end - start; + final it = iterable.skip(skipCount).take(size); + _allocate(sizeOf() * size, (ptr) { + it.forEachIndexed((index, element) { + ptr[index] = element; + }); + Jni.env.SetByteArrayRegion(reference, start, size, ptr); + }); + } +} + +extension CharArray on JArray { + String operator [](int index) { + return String.fromCharCode( + elementAt(index, JniCallType.charType).char, + ); + } + + void operator []=(int index, String value) { + RangeError.checkValidIndex(index, this); + _allocate(sizeOf(), (ptr) { + ptr.value = value.codeUnits.first; + Jni.env.SetCharArrayRegion(reference, index, 1, ptr); + }); + } + + void setRange(int start, int end, Iterable iterable, + [int skipCount = 0]) { + RangeError.checkValidRange(start, end, length); + final size = end - start; + final it = iterable.skip(skipCount).take(size); + _allocate(sizeOf() * size, (ptr) { + it.forEachIndexed((index, element) { + ptr[index] = element.codeUnits.first; + }); + Jni.env.SetCharArrayRegion(reference, start, size, ptr); + }); + } +} + +extension ShortArray on JArray { + int operator [](int index) { + return elementAt(index, JniCallType.shortType).short; + } + + void operator []=(int index, int value) { + RangeError.checkValidIndex(index, this); + _allocate(sizeOf(), (ptr) { + ptr.value = value; + Jni.env.SetShortArrayRegion(reference, index, 1, ptr); + }); + } + + void setRange(int start, int end, Iterable iterable, + [int skipCount = 0]) { + RangeError.checkValidRange(start, end, length); + final size = end - start; + final it = iterable.skip(skipCount).take(size); + _allocate(sizeOf() * size, (ptr) { + it.forEachIndexed((index, element) { + ptr[index] = element; + }); + Jni.env.SetShortArrayRegion(reference, start, size, ptr); + }); + } +} + +extension IntArray on JArray { + int operator [](int index) { + return elementAt(index, JniCallType.intType).integer; + } + + void operator []=(int index, int value) { + RangeError.checkValidIndex(index, this); + _allocate(sizeOf(), (ptr) { + ptr.value = value; + Jni.env.SetIntArrayRegion(reference, index, 1, ptr); + }); + } + + void setRange(int start, int end, Iterable iterable, + [int skipCount = 0]) { + RangeError.checkValidRange(start, end, length); + final size = end - start; + final it = iterable.skip(skipCount).take(size); + _allocate(sizeOf() * size, (ptr) { + it.forEachIndexed((index, element) { + ptr[index] = element; + }); + Jni.env.SetIntArrayRegion(reference, start, size, ptr); + }); + } +} + +extension LongArray on JArray { + int operator [](int index) { + return elementAt(index, JniCallType.longType).long; + } + + void operator []=(int index, int value) { + RangeError.checkValidIndex(index, this); + _allocate(sizeOf(), (ptr) { + ptr.value = value; + Jni.env.SetLongArrayRegion(reference, index, 1, ptr); + }); + } + + void setRange(int start, int end, Iterable iterable, + [int skipCount = 0]) { + RangeError.checkValidRange(start, end, length); + final size = end - start; + final it = iterable.skip(skipCount).take(size); + _allocate(sizeOf() * size, (ptr) { + it.forEachIndexed((index, element) { + ptr[index] = element; + }); + Jni.env.SetLongArrayRegion(reference, start, size, ptr); + }); + } +} + +extension FloatArray on JArray { + double operator [](int index) { + return elementAt(index, JniCallType.floatType).float; + } + + void operator []=(int index, double value) { + RangeError.checkValidIndex(index, this); + _allocate(sizeOf(), (ptr) { + ptr.value = value; + Jni.env.SetFloatArrayRegion(reference, index, 1, ptr); + }); + } + + void setRange(int start, int end, Iterable iterable, + [int skipCount = 0]) { + RangeError.checkValidRange(start, end, length); + final size = end - start; + final it = iterable.skip(skipCount).take(size); + _allocate(sizeOf() * size, (ptr) { + it.forEachIndexed((index, element) { + ptr[index] = element; + }); + Jni.env.SetFloatArrayRegion(reference, start, size, ptr); + }); + } +} + +extension DoubleArray on JArray { + double operator [](int index) { + return elementAt(index, JniCallType.doubleType).doubleFloat; + } + + void operator []=(int index, double value) { + RangeError.checkValidIndex(index, this); + _allocate(sizeOf(), (ptr) { + ptr.value = value; + Jni.env.SetDoubleArrayRegion(reference, index, 1, ptr); + }); + } + + void setRange(int start, int end, Iterable iterable, + [int skipCount = 0]) { + RangeError.checkValidRange(start, end, length); + final size = end - start; + final it = iterable.skip(skipCount).take(size); + _allocate(sizeOf() * size, (ptr) { + it.forEachIndexed((index, element) { + ptr[index] = element; + }); + Jni.env.SetDoubleArrayRegion(reference, start, size, ptr); + }); + } +} + +extension ObjectArray on JArray { + T operator [](int index) { + return (elementType as JObjType) + .fromRef(elementAt(index, JniCallType.objectType).object); + } + + void operator []=(int index, T value) { + RangeError.checkValidIndex(index, this); + Jni.env.SetObjectArrayElement(reference, index, value.reference); + } + + void setRange(int start, int end, Iterable iterable, [int skipCount = 0]) { + RangeError.checkValidRange(start, end, length); + final size = end - start; + final it = iterable.skip(skipCount).take(size); + it.forEachIndexed((index, element) { + this[index] = element; + }); + } +} diff --git a/pkgs/jni/lib/src/jfinal_string.dart b/pkgs/jni/lib/src/jfinal_string.dart new file mode 100644 index 000000000..ce3279981 --- /dev/null +++ b/pkgs/jni/lib/src/jfinal_string.dart @@ -0,0 +1,31 @@ +// Copyright (c) 2023, 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. + +import 'dart:ffi'; + +import 'jreference.dart'; +import 'lang/jstring.dart'; +import 'third_party/generated_bindings.dart'; + +/// Used for `static final` Java strings, where the constant string is +/// available. +/// +/// If only its value is used using [toDartString], the [reference] is never +/// populated, saving a method call. +class JFinalString extends JString with JLazyReference { + @override + final JObjectPtr Function() lazyReference; + + final String string; + + JFinalString(this.lazyReference, this.string) : super.fromRef(nullptr); + + @override + String toDartString({bool releaseOriginal = false}) { + if (releaseOriginal) { + release(); + } + return string; + } +} diff --git a/pkgs/jni/lib/src/jni.dart b/pkgs/jni/lib/src/jni.dart new file mode 100644 index 000000000..4993aee9d --- /dev/null +++ b/pkgs/jni/lib/src/jni.dart @@ -0,0 +1,383 @@ +// 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. + +import 'dart:ffi'; +import 'dart:io'; +import 'dart:isolate'; + +import 'package:ffi/ffi.dart'; +import 'package:path/path.dart'; + +import 'errors.dart'; +import 'jobject.dart'; +import 'third_party/generated_bindings.dart'; +import 'jvalues.dart'; +import 'accessors.dart'; + +String _getLibraryFileName(String base) { + if (Platform.isLinux || Platform.isAndroid) { + return "lib$base.so"; + } else if (Platform.isWindows) { + return "$base.dll"; + } else if (Platform.isMacOS) { + return "lib$base.dylib"; + } else { + throw UnsupportedError("cannot derive library name: unsupported platform"); + } +} + +/// Load Dart-JNI Helper library. +/// +/// If path is provided, it's used to load the library. +/// Else just the platform-specific filename is passed to DynamicLibrary.open +DynamicLibrary _loadDartJniLibrary({String? dir, String baseName = "dartjni"}) { + final fileName = _getLibraryFileName(baseName); + final libPath = (dir != null) ? join(dir, fileName) : fileName; + try { + final dylib = DynamicLibrary.open(libPath); + return dylib; + } on Error { + throw HelperNotFoundError(libPath); + } +} + +/// Utilities to spawn and manage JNI. +abstract final class Jni { + static final DynamicLibrary _dylib = _loadDartJniLibrary(dir: _dylibDir); + static final JniBindings _bindings = JniBindings(_dylib); + static final _getJniEnvFn = _dylib.lookup('GetJniEnv'); + static final _getJniContextFn = _dylib.lookup('GetJniContextPtr'); + + /// Store dylibDir if any was used. + static String? _dylibDir; + + /// Sets the directory where dynamic libraries are looked for. + /// On dart standalone, call this in new isolate before doing + /// any JNI operation. + /// + /// (The reason is that dylibs need to be loaded in every isolate. + /// On flutter it's done by library. On dart standalone we don't + /// know the library path.) + static void setDylibDir({required String dylibDir}) { + _dylibDir = dylibDir; + } + + /// Initializes DartApiDL used for Continuations and interface implementation. + static void initDLApi() { + assert(NativeApi.majorVersion == 2); + assert(NativeApi.minorVersion >= 3); + final result = _bindings.InitDartApiDL(NativeApi.initializeApiDLData); + assert(result == 0); + } + + /// Spawn an instance of JVM using JNI. This method should be called at the + /// beginning of the program with appropriate options, before other isolates + /// are spawned. + /// + /// [dylibDir] is path of the directory where the wrapper library is found. + /// This parameter needs to be passed manually on __Dart standalone target__, + /// since we have no reliable way to bundle it with the package. + /// + /// [jvmOptions], [ignoreUnrecognized], & [jniVersion] are passed to the JVM. + /// Strings in [classPath], if any, are used to construct an additional + /// JVM option of the form "-Djava.class.path={paths}". + static void spawn({ + String? dylibDir, + List jvmOptions = const [], + List classPath = const [], + bool ignoreUnrecognized = false, + int jniVersion = JniVersions.JNI_VERSION_1_6, + }) { + final status = spawnIfNotExists( + dylibDir: dylibDir, + jvmOptions: jvmOptions, + classPath: classPath, + ignoreUnrecognized: ignoreUnrecognized, + jniVersion: jniVersion, + ); + if (status == false) { + throw JniVmExistsError(); + } + } + + /// Same as [spawn] but if a JVM exists, returns silently instead of + /// throwing [JvmExistsError]. + /// + /// If the options are different than that of existing VM, the existing VM's + /// options will remain in effect. + static bool spawnIfNotExists({ + String? dylibDir, + List jvmOptions = const [], + List classPath = const [], + bool ignoreUnrecognized = false, + int jniVersion = JniVersions.JNI_VERSION_1_6, + }) => + using((arena) { + _dylibDir = dylibDir; + final jvmArgs = _createVMArgs( + options: jvmOptions, + classPath: classPath, + version: jniVersion, + dylibPath: dylibDir, + ignoreUnrecognized: ignoreUnrecognized, + allocator: arena, + ); + final status = _bindings.SpawnJvm(jvmArgs); + if (status == JniErrorCode.JNI_OK) { + return true; + } else if (status == DART_JNI_SINGLETON_EXISTS) { + return false; + } else { + throw JniError.of(status); + } + }); + + static Pointer _createVMArgs({ + List options = const [], + List classPath = const [], + String? dylibPath, + bool ignoreUnrecognized = false, + int version = JniVersions.JNI_VERSION_1_6, + required Allocator allocator, + }) { + final args = allocator(); + if (options.isNotEmpty || classPath.isNotEmpty) { + final count = options.length + + (dylibPath != null ? 1 : 0) + + (classPath.isNotEmpty ? 1 : 0); + final optsPtr = (count != 0) ? allocator(count) : nullptr; + args.ref.options = optsPtr; + for (int i = 0; i < options.length; i++) { + optsPtr.elementAt(i).ref.optionString = + options[i].toNativeChars(allocator); + } + if (dylibPath != null) { + optsPtr + .elementAt(count - 1 - (classPath.isNotEmpty ? 1 : 0)) + .ref + .optionString = + "-Djava.library.path=$dylibPath".toNativeChars(allocator); + } + if (classPath.isNotEmpty) { + final classPathString = classPath.join(Platform.isWindows ? ';' : ":"); + optsPtr.elementAt(count - 1).ref.optionString = + "-Djava.class.path=$classPathString".toNativeChars(allocator); + } + args.ref.nOptions = count; + } + args.ref.ignoreUnrecognized = ignoreUnrecognized ? 1 : 0; + args.ref.version = version; + return args; + } + + /// Returns pointer to current JNI JavaVM instance + Pointer getJavaVM() { + return _bindings.GetJavaVM(); + } + + /// Returns the instance of [GlobalJniEnvStruct], which is an abstraction over + /// JNIEnv without the same-thread restriction. + static Pointer _fetchGlobalEnv() { + final env = _bindings.GetGlobalEnv(); + if (env == nullptr) { + throw NoJvmInstanceError(); + } + return env; + } + + /// Points to a process-wide shared instance of [GlobalJniEnv]. + /// + /// It provides an indirection over [JniEnv] so that it can be used from + /// any thread, and always returns global object references. + static final env = GlobalJniEnv(_fetchGlobalEnv()); + + static final accessors = JniAccessors(_bindings.GetAccessors()); + + /// Returns current application context on Android. + static JObjectPtr getCachedApplicationContext() { + return _bindings.GetApplicationContext(); + } + + /// Returns current activity + static JObjectPtr getCurrentActivity() => _bindings.GetCurrentActivity(); + + /// Get the initial classLoader of the application. + /// + /// This is especially useful on Android, where + /// JNI threads cannot access application classes using + /// the usual `JniEnv.FindClass` method. + static JObjectPtr getApplicationClassLoader() => _bindings.GetClassLoader(); + + /// Returns class reference found through system-specific mechanism + static JClassPtr findClass(String qualifiedName) => using((arena) { + final cls = accessors.getClass(qualifiedName.toNativeChars(arena)); + return cls.checkedClassRef; + }); + + /// Returns class for [qualifiedName] found by platform-specific mechanism, + /// wrapped in a [JClass]. + static JClass findJClass(String qualifiedName) => + JClass.fromRef(findClass(qualifiedName)); + + /// Constructs an instance of class with given arguments. + /// + /// Use it when one instance is needed, but the constructor or class aren't + /// required themselves. + static JObject newInstance( + String qualifiedName, String ctorSignature, List args) { + final cls = findJClass(qualifiedName); + final ctor = cls.getCtorID(ctorSignature); + final obj = cls.newInstance(ctor, args); + cls.release(); + return obj; + } + + /// Converts passed arguments to JValue array. + /// + /// long, bool, double and JObject types are converted out of the box. + /// Wrap values in types such as [JValueInt] to convert to other primitive + /// types such as `int`, `short` and `char`. + static Pointer jvalues(List args, + {Allocator allocator = calloc}) { + return toJValues(args, allocator: allocator); + } + + /// Returns the value of static field identified by [fieldName] & [signature]. + /// + /// See [JObject.getField] for more explanations about [callType] and [T]. + static T retrieveStaticField( + String className, String fieldName, String signature, + [int? callType]) { + final cls = findJClass(className); + final result = cls.getStaticFieldByName(fieldName, signature, callType); + cls.release(); + return result; + } + + /// Calls static method identified by [methodName] and [signature] + /// on [className] with [args] as and [callType]. + /// + /// For more explanation on [args] and [callType], see [JObject.getField] + /// and [JObject.callMethod] respectively. + static T invokeStaticMethod( + String className, String methodName, String signature, List args, + [int? callType]) { + final cls = findJClass(className); + final result = + cls.callStaticMethodByName(methodName, signature, args, callType); + cls.release(); + return result; + } +} + +typedef _SetJniGettersNativeType = Void Function(Pointer, Pointer); +typedef _SetJniGettersDartType = void Function(Pointer, Pointer); + +/// Extensions for use by `jnigen` generated code. +extension ProtectedJniExtensions on Jni { + static Pointer Function(String) initGeneratedLibrary( + String name) { + var path = _getLibraryFileName(name); + if (Jni._dylibDir != null) { + path = join(Jni._dylibDir!, path); + } + final dl = DynamicLibrary.open(path); + final setJniGetters = + dl.lookupFunction<_SetJniGettersNativeType, _SetJniGettersDartType>( + 'setJniGetters'); + setJniGetters(Jni._getJniContextFn, Jni._getJniEnvFn); + final lookup = dl.lookup; + return lookup; + } + + /// Returns a new DartException. + static JObjectPtr newDartException(String message) { + return Jni._bindings + .DartException__ctor(Jni.env.toJStringPtr(message)) + .object; + } + + /// Returns a new PortContinuation. + static JObjectPtr newPortContinuation(ReceivePort port) { + return Jni._bindings + .PortContinuation__ctor(port.sendPort.nativePort) + .object; + } + + /// Returns a new PortProxy for a class with the given [binaryName]. + static JObjectPtr newPortProxy( + String binaryName, + ReceivePort port, + Pointer< + NativeFunction< + Pointer Function(Uint64, Pointer, Pointer)>> + functionPtr) { + return Jni._bindings + .PortProxy__newInstance( + Jni.env.toJStringPtr(binaryName), + port.sendPort.nativePort, + functionPtr.address, + ) + .object; + } + + /// Returns the result of a callback.. + static void returnResult( + Pointer result, JObjectPtr object) async { + Jni._bindings.resultFor(result, object); + } +} + +extension AdditionalEnvMethods on GlobalJniEnv { + /// Convenience method for converting a [JStringPtr] to dart string. + /// if [releaseOriginal] is specified, jstring passed will be deleted using + /// DeleteGlobalRef. + String toDartString(JStringPtr jstringPtr, {bool releaseOriginal = false}) { + if (jstringPtr == nullptr) { + throw JNullError(); + } + final chars = GetStringChars(jstringPtr, nullptr); + if (chars == nullptr) { + throw ArgumentError('Not a valid jstring pointer.'); + } + final length = GetStringLength(jstringPtr); + final result = chars.cast().toDartString(length: length); + ReleaseStringChars(jstringPtr, chars); + if (releaseOriginal) { + DeleteGlobalRef(jstringPtr); + } + return result; + } + + /// Returns a new [JStringPtr] from contents of [s]. + JStringPtr toJStringPtr(String s) => using((arena) { + final utf = s.toNativeUtf16(allocator: arena).cast(); + final result = NewString(utf, s.length); + if (utf == nullptr) { + throw 'Fatal: cannot convert string to Java string: $s'; + } + return result; + }); + + /// Deletes all references in [refs]. + void deleteAllRefs(List refs) { + for (final ref in refs) { + DeleteGlobalRef(ref); + } + } +} + +extension StringMethodsForJni on String { + /// Returns a Utf-8 encoded Pointer with contents same as this string. + Pointer toNativeChars([Allocator allocator = malloc]) { + return toNativeUtf8(allocator: allocator).cast(); + } +} + +extension CharPtrMethodsForJni on Pointer { + /// Same as calling `cast` followed by `toDartString`. + String toDartString({int? length}) { + return cast().toDartString(length: length); + } +} diff --git a/pkgs/jni/lib/src/jobject.dart b/pkgs/jni/lib/src/jobject.dart new file mode 100644 index 000000000..15c69727e --- /dev/null +++ b/pkgs/jni/lib/src/jobject.dart @@ -0,0 +1,431 @@ +// 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. + +import 'dart:ffi'; + +import 'package:ffi/ffi.dart'; +import 'package:jni/src/accessors.dart'; + +import 'errors.dart'; +import 'jni.dart'; +import 'jreference.dart'; +import 'lang/jstring.dart'; +import 'jvalues.dart'; +import 'third_party/generated_bindings.dart'; +import 'types.dart'; + +// This typedef is needed because void is a keyword and cannot be used in +// type switch like a regular type. +typedef _VoidType = void; + +final class JObjectType extends JObjType { + const JObjectType(); + + @override + String get signature => "Ljava/lang/Object;"; + + @override + JObject fromRef(Pointer ref) => JObject.fromRef(ref); + + @override + JObjType get superType => const JObjectType(); + + // TODO(#70): Once interface implementation lands, other than [superType], + // we should have a list of implemented interfaces. + + @override + final int superCount = 0; + + @override + int get hashCode => (JObjectType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == JObjectType && other is JObjectType; + } +} + +Pointer _getID( + JniPointerResult Function( + Pointer ptr, Pointer name, Pointer sig) + f, + Pointer ptr, + String name, + String sig, +) { + final result = using( + (arena) => f(ptr, name.toNativeChars(arena), sig.toNativeChars(arena))); + if (result.exception != nullptr) { + Jni.accessors.throwException(result.exception); + } + return result.value.cast(); +} + +int _getCallType(int? callType, int defaultType, Set allowed) { + if (callType == null) return defaultType; + if (allowed.contains(callType)) return callType; + throw InvalidCallTypeError(callType, allowed); +} + +T _callOrGet(int? callType, JniResult Function(int) function) { + final int finalCallType; + late T result; + switch (T) { + case bool: + finalCallType = _getCallType( + callType, JniCallType.booleanType, {JniCallType.booleanType}); + result = function(finalCallType).boolean as T; + break; + case int: + finalCallType = _getCallType(callType, JniCallType.longType, { + JniCallType.byteType, + JniCallType.charType, + JniCallType.shortType, + JniCallType.intType, + JniCallType.longType, + }); + final jniResult = function(finalCallType); + switch (finalCallType) { + case JniCallType.byteType: + result = jniResult.byte as T; + break; + case JniCallType.shortType: + result = jniResult.short as T; + break; + case JniCallType.charType: + result = jniResult.char as T; + break; + case JniCallType.intType: + result = jniResult.integer as T; + break; + case JniCallType.longType: + result = jniResult.long as T; + break; + } + break; + case double: + finalCallType = _getCallType(callType, JniCallType.doubleType, + {JniCallType.floatType, JniCallType.doubleType}); + final jniResult = function(finalCallType); + switch (finalCallType) { + case JniCallType.floatType: + result = jniResult.float as T; + break; + case JniCallType.doubleType: + result = jniResult.doubleFloat as T; + break; + } + break; + case String: + case JObject: + case JString: + finalCallType = _getCallType( + callType, JniCallType.objectType, {JniCallType.objectType}); + final ref = function(finalCallType).object; + final ctor = T == String + ? (ref) => Jni.env.toDartString(ref, releaseOriginal: true) + : (T == JObject ? JObject.fromRef : JString.fromRef); + result = ctor(ref) as T; + break; + case const (Pointer): // JObjectPtr + finalCallType = _getCallType( + callType, JniCallType.objectType, {JniCallType.objectType}); + result = function(finalCallType).object as T; + break; + case _VoidType: + finalCallType = + _getCallType(callType, JniCallType.voidType, {JniCallType.voidType}); + function(finalCallType).check(); + result = null as T; + break; + case dynamic: + throw UnsupportedError("Return type not specified for JNI call"); + default: + throw UnsupportedError('Unknown type $T'); + } + return result; +} + +T _callMethod(int? callType, List args, + JniResult Function(int, Pointer) f) => + using((arena) { + final jArgs = JValueArgs(args, arena); + return _callOrGet(callType, (ct) => f(ct, jArgs.values)); + }); + +T _getField(int? callType, JniResult Function(int) f) { + final result = _callOrGet(callType, f); + return result; +} + +/// A high-level wrapper for JNI global object reference. +/// +/// This is the base class for classes generated by `jnigen`. +class JObject extends JReference { + late final JObjType $type = type; + + /// The type which includes information such as the signature of this class. + static const JObjType type = JObjectType(); + + /// Construct a new [JObject] with [reference] as its underlying reference. + JObject.fromRef(JObjectPtr reference) : super.fromRef(reference); + + JClass? _jClass; + + JClass get _class { + return _jClass ??= getClass(); + } + + @override + void release() { + _jClass?.release(); + super.release(); + } + + /// Returns [JClass] corresponding to concrete class of this object. + /// + /// This may be a subclass of compile-time class. + JClass getClass() { + final classRef = Jni.env.GetObjectClass(reference); + if (classRef == nullptr) { + Jni.accessors.throwException(Jni.env.ExceptionOccurred()); + } + return JClass.fromRef(classRef); + } + + /// Get [JFieldIDPtr] of instance field identified by [fieldName] & [signature]. + JFieldIDPtr getFieldID(String fieldName, String signature) { + return _getID( + Jni.accessors.getFieldID, _class.reference, fieldName, signature); + } + + /// Get [JFieldIDPtr] of static field identified by [fieldName] & [signature]. + JFieldIDPtr getStaticFieldID(String fieldName, String signature) { + return _getID( + Jni.accessors.getStaticFieldID, _class.reference, fieldName, signature); + } + + /// Get [JMethodIDPtr] of instance method [methodName] with [signature]. + JMethodIDPtr getMethodID(String methodName, String signature) { + return _getID( + Jni.accessors.getMethodID, _class.reference, methodName, signature); + } + + /// Get [JMethodIDPtr] of static method [methodName] with [signature]. + JMethodIDPtr getStaticMethodID(String methodName, String signature) { + return _getID(Jni.accessors.getStaticMethodID, _class.reference, + methodName, signature); + } + + /// Retrieve the value of the field using [fieldID]. + /// + /// [callType] determines the return type of the underlying JNI call made. + /// If the Java field is of `long` type, this must be [JniCallType.longType] and + /// so on. Default is chosen based on return type [T], which maps int -> int, + /// double -> double, void -> void, and JObject types to `Object`. + /// + /// If [T] is String or [JObject], required conversions are performed and + /// final value is returned. + T getField(JFieldIDPtr fieldID, [int? callType]) { + if (callType == JniCallType.voidType) { + throw ArgumentError("void is not a valid field type."); + } + return _getField( + callType, (ct) => Jni.accessors.getField(reference, fieldID, ct)); + } + + /// Get value of the field identified by [name] and [signature]. + /// + /// See [getField] for an explanation about [callType] parameter. + T getFieldByName(String name, String signature, [int? callType]) { + final id = getFieldID(name, signature); + return getField(id, callType); + } + + /// Get value of the static field using [fieldID]. + /// + /// See [getField] for an explanation about [callType] parameter. + T getStaticField(JFieldIDPtr fieldID, [int? callType]) { + if (callType == JniCallType.voidType) { + throw ArgumentError("void is not a valid field type."); + } + return _getField(callType, + (ct) => Jni.accessors.getStaticField(_class.reference, fieldID, ct)); + } + + /// Get value of the static field identified by [name] and [signature]. + /// + /// See [getField] for an explanation about [callType] parameter. + T getStaticFieldByName(String name, String signature, [int? callType]) { + final id = getStaticFieldID(name, signature); + return getStaticField(id, callType); + } + + /// Call the method using [methodID], + /// + /// [args] can consist of primitive types, JNI primitive wrappers such as + /// [JValueLong], strings, and subclasses of [JObject]. + /// + /// See [getField] for an explanation about [callType] and return type [T]. + T callMethod(JMethodIDPtr methodID, List args, [int? callType]) { + return _callMethod(callType, args, + (ct, jvs) => Jni.accessors.callMethod(reference, methodID, ct, jvs)); + } + + /// Call instance method identified by [name] and [signature]. + /// + /// This implementation looks up the method and calls it using [callMethod]. + T callMethodByName(String name, String signature, List args, + [int? callType]) { + final id = getMethodID(name, signature); + return callMethod(id, args, callType); + } + + /// Call static method using [methodID]. See [callMethod] and [getField] for + /// more details about [args] and [callType]. + T callStaticMethod(JMethodIDPtr methodID, List args, + [int? callType]) { + return _callMethod( + callType, + args, + (ct, jvs) => + Jni.accessors.callStaticMethod(reference, methodID, ct, jvs)); + } + + /// Call static method identified by [name] and [signature]. + /// + /// This implementation looks up the method and calls [callStaticMethod]. + T callStaticMethodByName(String name, String signature, List args, + [int? callType]) { + final id = getStaticMethodID(name, signature); + return callStaticMethod(id, args, callType); + } + + /// Casts this object to another [type]. + /// + /// If [releaseOriginal] is `true`, the casted object will be released. + T castTo( + JObjType type, { + bool releaseOriginal = false, + }) { + if (releaseOriginal) { + _jClass?.release(); + final ret = type.fromRef(reference); + setAsReleased(); + return ret; + } + final newRef = Jni.env.NewGlobalRef(reference); + return type.fromRef(newRef); + } + + static final _objectClass = Jni.findJClass('java/lang/Object'); + + static final _hashCodeId = + Jni.accessors.getMethodIDOf(_objectClass.reference, r"hashCode", r"()I"); + @override + int get hashCode => Jni.accessors.callMethodWithArgs( + reference, _hashCodeId, JniCallType.intType, []).integer; + + static final _equalsId = Jni.accessors.getMethodIDOf( + _objectClass.reference, r"equals", r"(Ljava/lang/Object;)Z"); + @override + bool operator ==(Object other) { + if (other is! JObject) { + return false; + } + return Jni.accessors.callMethodWithArgs(reference, _equalsId, + JniCallType.booleanType, [other.reference]).boolean; + } + + static final _toStringId = Jni.accessors.getMethodIDOf( + _objectClass.reference, r"toString", r"()Ljava/lang/String;"); + @override + String toString() { + return JString.fromRef(Jni.accessors.callMethodWithArgs( + reference, _toStringId, JniCallType.objectType, []).object) + .toDartString(releaseOriginal: true); + } +} + +/// A high level wrapper over a JNI class reference. +class JClass extends JReference { + /// Construct a new [JClass] with [reference] as its underlying reference. + JClass.fromRef(JObjectPtr reference) : super.fromRef(reference); + + /// Get [JFieldIDPtr] of static field [fieldName] with [signature]. + JFieldIDPtr getStaticFieldID(String fieldName, String signature) { + return _getID( + Jni.accessors.getStaticFieldID, reference, fieldName, signature); + } + + /// Get [JMethodIDPtr] of static method [methodName] with [signature]. + JMethodIDPtr getStaticMethodID(String methodName, String signature) { + return _getID( + Jni.accessors.getStaticMethodID, reference, methodName, signature); + } + + /// Get [JFieldIDPtr] of field [fieldName] with [signature]. + JFieldIDPtr getFieldID(String fieldName, String signature) { + return _getID( + Jni.accessors.getFieldID, reference, fieldName, signature); + } + + /// Get [JMethodIDPtr] of method [methodName] with [signature]. + JMethodIDPtr getMethodID(String methodName, String signature) { + return _getID( + Jni.accessors.getMethodID, reference, methodName, signature); + } + + /// Get [JMethodIDPtr] of constructor with [signature]. + JMethodIDPtr getCtorID(String signature) => getMethodID("", signature); + + /// Get the value of static field using [fieldID]. + /// + /// See [JObject.getField] for more explanation about [callType]. + T getStaticField(JFieldIDPtr fieldID, [int? callType]) { + if (callType == JniCallType.voidType) { + throw ArgumentError("void is not a valid field type."); + } + return _getField( + callType, (ct) => Jni.accessors.getStaticField(reference, fieldID, ct)); + } + + /// Get the value of static field identified by [name] and [signature]. + /// + /// This implementation looks up the field ID and calls [getStaticField]. + T getStaticFieldByName(String name, String signature, [int? callType]) { + final id = getStaticFieldID(name, signature); + return getStaticField(id, callType); + } + + /// Call the static method using [methodID]. + /// + /// See [JObject.callMethod] and [JObject.getField] for more explanation + /// about [args] and [callType]. + T callStaticMethod(JMethodIDPtr methodID, List args, + [int? callType]) { + return _callMethod( + callType, + args, + (ct, jvs) => + Jni.accessors.callStaticMethod(reference, methodID, ct, jvs)); + } + + /// Call the static method identified by [name] and [signature]. + /// + /// This implementation looks up the method ID and calls [callStaticMethod]. + T callStaticMethodByName(String name, String signature, List args, + [int? callType]) { + final id = getStaticMethodID(name, signature); + return callStaticMethod(id, args, callType); + } + + /// Create a new instance of this class with [ctor] and [args]. + JObject newInstance(JMethodIDPtr ctor, List args) => using((arena) { + final jArgs = JValueArgs(args, arena); + final res = + Jni.accessors.newObject(reference, ctor, jArgs.values).object; + return JObject.fromRef(res); + }); +} diff --git a/pkgs/jni/lib/src/jprimitives.dart b/pkgs/jni/lib/src/jprimitives.dart new file mode 100644 index 000000000..04448da2c --- /dev/null +++ b/pkgs/jni/lib/src/jprimitives.dart @@ -0,0 +1,99 @@ +// 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. + +// The types here are mapped to primitive types in Java, so they're all in +// lowercase. +// ignore_for_file: camel_case_types + +part of 'types.dart'; + +abstract final class JPrimitive {} + +abstract final class jbyte extends JPrimitive { + static const type = jbyteType(); +} + +final class jbyteType extends JType { + const jbyteType(); + + @override + final signature = 'B'; +} + +abstract final class jboolean extends JPrimitive { + static const type = jbooleanType(); +} + +final class jbooleanType extends JType { + const jbooleanType(); + + @override + final signature = 'Z'; +} + +abstract final class jchar extends JPrimitive { + static const type = jcharType(); +} + +final class jcharType extends JType { + const jcharType(); + + @override + final signature = 'C'; +} + +abstract final class jshort extends JPrimitive { + static const type = jshortType(); +} + +final class jshortType extends JType { + const jshortType(); + + @override + final signature = 'S'; +} + +abstract final class jint extends JPrimitive { + static const type = jintType(); +} + +final class jintType extends JType { + const jintType(); + + @override + final signature = 'I'; +} + +abstract final class jlong extends JPrimitive { + static const type = jlongType(); +} + +final class jlongType extends JType { + const jlongType(); + + @override + final signature = 'J'; +} + +abstract final class jfloat extends JPrimitive { + static const type = jfloatType(); +} + +final class jfloatType extends JType { + const jfloatType(); + + @override + final signature = 'F'; +} + +abstract final class jdouble extends JPrimitive { + static const type = jdoubleType(); +} + +final class jdoubleType extends JType { + const jdoubleType(); + + @override + final signature = 'D'; +} diff --git a/pkgs/jni/lib/src/jreference.dart b/pkgs/jni/lib/src/jreference.dart new file mode 100644 index 000000000..093e297df --- /dev/null +++ b/pkgs/jni/lib/src/jreference.dart @@ -0,0 +1,136 @@ +// 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. + +import 'dart:ffi'; + +import 'package:ffi/ffi.dart'; +import 'package:jni/src/third_party/generated_bindings.dart'; + +import 'errors.dart'; +import 'jni.dart'; + +extension ProtectedJReference on JReference { + void setAsReleased() { + if (_released) { + throw DoubleReleaseError(); + } + _released = true; + JReference._finalizer.detach(this); + } + + void ensureNotNull() { + if (isNull) { + throw JNullError(); + } + } + + /// Similar to [reference]. + /// + /// Detaches the finalizer so the underlying pointer will not be deleted. + JObjectPtr toPointer() { + final ref = reference; + setAsReleased(); + return ref; + } +} + +/// A managed JNI global reference. +/// +/// Uses a [NativeFinalizer] to delete the JNI global reference when finalized. +abstract class JReference implements Finalizable { + static final _finalizer = + NativeFinalizer(Jni.env.ptr.ref.DeleteGlobalRef.cast()); + + JReference.fromRef(this._reference) { + if (_reference != nullptr) { + _finalizer.attach(this, _reference, detach: this); + } + } + + bool _released = false; + + /// Whether the underlying JNI reference is `null` or not. + bool get isNull => reference == nullptr; + + /// Whether the underlying JNI reference is deleted or not. + bool get isReleased => _released; + + /// Deletes the underlying JNI reference and marks this as released. + /// + /// Throws [DoubleReleaseError] if this is already released. + /// + /// Further uses of this object will throw [UseAfterReleaseError]. + void release() { + setAsReleased(); + Jni.env.DeleteGlobalRef(_reference); + } + + /// The underlying JNI global object reference. + /// + /// Throws [UseAfterReleaseError] if the object is previously released. + /// + /// Be careful when storing this in a variable since it might have gotten + /// released upon use. + JObjectPtr get reference { + if (_released) throw UseAfterReleaseError(); + return _reference; + } + + final JObjectPtr _reference; + + /// Registers this object to be released at the end of [arena]'s lifetime. + void releasedBy(Arena arena) => arena.onReleaseAll(release); +} + +/// Creates a "lazy" [JReference]. +/// +/// The first use of [reference] will call [lazyReference]. +/// +/// This is useful when the Java object is not necessarily used directly, and +/// there are alternative ways to get a Dart representation of the Object. +/// +/// Object mixed in with this must call their super.[fromRef] constructor +/// with [nullptr]. +/// +/// Also see [JFinalString]. +mixin JLazyReference on JReference { + JObjectPtr? _lazyReference; + + JObjectPtr Function() get lazyReference; + + @override + JObjectPtr get reference { + if (_lazyReference == null) { + _lazyReference = lazyReference(); + JReference._finalizer.attach(this, _lazyReference!, detach: this); + return _lazyReference!; + } + if (_released) { + throw UseAfterReleaseError(); + } + return _lazyReference!; + } + + @override + void release() { + setAsReleased(); + if (_lazyReference == null) { + return; + } + Jni.env.DeleteGlobalRef(_lazyReference!); + } +} + +extension JReferenceUseExtension on T { + /// Applies [callback] on [this] object and then delete the underlying JNI + /// reference, returning the result of [callback]. + R use(R Function(T) callback) { + try { + final result = callback(this); + return result; + } finally { + release(); + } + } +} diff --git a/pkgs/jni/lib/src/jvalues.dart b/pkgs/jni/lib/src/jvalues.dart new file mode 100644 index 000000000..dc1773617 --- /dev/null +++ b/pkgs/jni/lib/src/jvalues.dart @@ -0,0 +1,144 @@ +// 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. + +import 'dart:ffi'; +import 'package:ffi/ffi.dart'; + +import 'jobject.dart'; +import 'third_party/generated_bindings.dart'; +import 'jni.dart'; + +void _fillJValue(Pointer pos, dynamic arg) { + if (arg is JObject) { + pos.ref.l = arg.reference; + return; + } + + switch (arg.runtimeType) { + case int: + pos.ref.j = arg; + break; + case bool: + pos.ref.z = arg ? 1 : 0; + break; + case const (Pointer): + case const (Pointer): // for nullptr + pos.ref.l = arg; + break; + case double: + pos.ref.d = arg; + break; + case JValueFloat: + pos.ref.f = (arg as JValueFloat).value; + break; + case JValueInt: + pos.ref.i = (arg as JValueInt).value; + break; + case JValueShort: + pos.ref.s = (arg as JValueShort).value; + break; + case JValueChar: + pos.ref.c = (arg as JValueChar).value; + break; + case JValueByte: + pos.ref.b = (arg as JValueByte).value; + break; + default: + throw UnsupportedError("cannot convert ${arg.runtimeType} to jvalue"); + } +} + +/// Converts passed arguments to JValue array +/// for use in methods that take arguments. +/// +/// int, bool, double and JObject types are converted out of the box. +/// wrap values in types such as [JValueLong] +/// to convert to other primitive types instead. +Pointer toJValues(List args, {Allocator allocator = calloc}) { + final result = allocator(args.length); + for (int i = 0; i < args.length; i++) { + final arg = args[i]; + final pos = result.elementAt(i); + _fillJValue(pos, arg); + } + return result; +} + +/// Use this class as wrapper to convert an integer +/// to Java `int` in jvalues method. +final class JValueInt { + int value; + JValueInt(this.value); +} + +/// Use this class as wrapper to convert an integer +/// to Java `short` in jvalues method. +final class JValueShort { + int value; + JValueShort(this.value); +} + +/// Use this class as wrapper to convert an integer +/// to Java `byte` in jvalues method. +final class JValueByte { + int value; + JValueByte(this.value); +} + +/// Use this class as wrapper to convert an double +/// to Java `float` in jvalues method. +final class JValueFloat { + double value; + JValueFloat(this.value); +} + +/// Use this class as wrapper to convert an integer +/// to Java `char` in jvalues method. +final class JValueChar { + int value; + JValueChar(this.value); + JValueChar.fromString(String s) : value = 0 { + if (s.length != 1) { + throw "Expected string of length 1"; + } + value = s.codeUnitAt(0).toInt(); + } +} + +/// class used to convert dart types passed to convenience methods +/// into their corresponding Java values. +/// +/// Similar to Jni.jvalues, but instead of a pointer, an instance +/// with a dispose method is returned. +/// This allows us to take dart strings. +/// +/// Returned value is allocated using provided allocator. +/// But default allocator may be used for string conversions. +final class JValueArgs { + late Pointer values; + final List createdRefs = []; + + JValueArgs(List args, Arena arena) { + values = arena(args.length); + for (int i = 0; i < args.length; i++) { + final arg = args[i]; + final ptr = values.elementAt(i); + if (arg is String) { + final jstr = Jni.env.toJStringPtr(arg); + ptr.ref.l = jstr; + createdRefs.add(jstr); + } else { + _fillJValue(ptr, arg); + } + arena.onReleaseAll(_dispose); + } + } + + /// Deletes temporary references such as [JStringPtr]s. + void _dispose() { + for (var ref in createdRefs) { + Jni.env.DeleteGlobalRef(ref); + } + } +} diff --git a/pkgs/jni/lib/src/lang/jboolean.dart b/pkgs/jni/lib/src/lang/jboolean.dart new file mode 100644 index 000000000..9ea92b436 --- /dev/null +++ b/pkgs/jni/lib/src/lang/jboolean.dart @@ -0,0 +1,68 @@ +// Copyright (c) 2023, 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. + +import '../accessors.dart'; +import '../jobject.dart'; +import '../jreference.dart'; +import '../jni.dart'; +import '../third_party/generated_bindings.dart'; +import '../types.dart'; + +final class JBooleanType extends JObjType { + const JBooleanType(); + + @override + String get signature => r"Ljava/lang/Boolean;"; + + @override + JBoolean fromRef(JObjectPtr ref) => JBoolean.fromRef(ref); + + @override + JObjType get superType => const JObjectType(); + + @override + final superCount = 2; + + @override + int get hashCode => (JBooleanType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == JBooleanType && other is JBooleanType; + } +} + +class JBoolean extends JObject { + @override + // ignore: overridden_fields + late final JObjType $type = type; + + JBoolean.fromRef( + JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = JBooleanType(); + + static final _class = Jni.findJClass(r"java/lang/Boolean"); + + static final _ctorId = + Jni.accessors.getMethodIDOf(_class.reference, r"", r"(Z)V"); + JBoolean(bool boolean) + : super.fromRef(Jni.accessors.newObjectWithArgs( + _class.reference, _ctorId, [boolean ? 1 : 0]).object); + + static final _booleanValueId = + Jni.accessors.getMethodIDOf(_class.reference, r"booleanValue", r"()Z"); + + bool booleanValue({bool releaseOriginal = false}) { + ensureNotNull(); + final ret = Jni.accessors.callMethodWithArgs( + reference, _booleanValueId, JniCallType.booleanType, []).boolean; + if (releaseOriginal) { + release(); + } + return ret; + } +} diff --git a/pkgs/jni/lib/src/lang/jbyte.dart b/pkgs/jni/lib/src/lang/jbyte.dart new file mode 100644 index 000000000..6b5aa9808 --- /dev/null +++ b/pkgs/jni/lib/src/lang/jbyte.dart @@ -0,0 +1,55 @@ +// Copyright (c) 2023, 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. + +import '../accessors.dart'; +import '../jni.dart'; +import '../jvalues.dart'; +import '../third_party/generated_bindings.dart'; +import '../types.dart'; +import 'jnumber.dart'; + +final class JByteType extends JObjType { + const JByteType(); + + @override + String get signature => r"Ljava/lang/Byte;"; + + @override + JByte fromRef(JObjectPtr ref) => JByte.fromRef(ref); + + @override + JObjType get superType => const JNumberType(); + + @override + final superCount = 2; + + @override + int get hashCode => (JByteType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == JByteType && other is JByteType; + } +} + +class JByte extends JNumber { + @override + // ignore: overridden_fields + late final JObjType $type = type; + + JByte.fromRef( + JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = JByteType(); + + static final _class = Jni.findJClass(r"java/lang/Byte"); + + static final _ctorId = + Jni.accessors.getMethodIDOf(_class.reference, r"", r"(B)V"); + JByte(int num) + : super.fromRef(Jni.accessors.newObjectWithArgs( + _class.reference, _ctorId, [JValueByte(num)]).object); +} diff --git a/pkgs/jni/lib/src/lang/jcharacter.dart b/pkgs/jni/lib/src/lang/jcharacter.dart new file mode 100644 index 000000000..b50f67f45 --- /dev/null +++ b/pkgs/jni/lib/src/lang/jcharacter.dart @@ -0,0 +1,66 @@ +import '../accessors.dart'; +import '../jni.dart'; +import '../jobject.dart'; +import '../jreference.dart'; +import '../jvalues.dart'; +import '../third_party/generated_bindings.dart'; +import '../types.dart'; + +final class JCharacterType extends JObjType { + const JCharacterType(); + + @override + String get signature => r"Ljava/lang/Character;"; + + @override + JCharacter fromRef(JObjectPtr ref) => JCharacter.fromRef(ref); + + @override + JObjType get superType => const JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => (JCharacterType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == (JCharacterType) && other is JCharacterType; + } +} + +class JCharacter extends JObject { + @override + // ignore: overridden_fields + late final JObjType $type = type; + + JCharacter.fromRef( + JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = JCharacterType(); + + static final _class = Jni.findJClass(r"java/lang/Character"); + + static final _ctorId = + Jni.accessors.getMethodIDOf(_class.reference, r"", r"(C)V"); + + JCharacter(int c) + : super.fromRef(Jni.accessors.newObjectWithArgs( + _class.reference, _ctorId, [JValueChar(c)]).object); + + static final _charValueId = + Jni.accessors.getMethodIDOf(_class.reference, r"charValue", r"()C"); + + int charValue({bool releaseOriginal = false}) { + ensureNotNull(); + final ret = Jni.accessors.callMethodWithArgs( + reference, _charValueId, JniCallType.charType, []).char; + if (releaseOriginal) { + release(); + } + return ret; + } +} diff --git a/pkgs/jni/lib/src/lang/jdouble.dart b/pkgs/jni/lib/src/lang/jdouble.dart new file mode 100644 index 000000000..6db163e4e --- /dev/null +++ b/pkgs/jni/lib/src/lang/jdouble.dart @@ -0,0 +1,54 @@ +// Copyright (c) 2023, 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. + +import '../accessors.dart'; +import '../jni.dart'; +import '../third_party/generated_bindings.dart'; +import '../types.dart'; +import 'jnumber.dart'; + +final class JDoubleType extends JObjType { + const JDoubleType(); + + @override + String get signature => r"Ljava/lang/Double;"; + + @override + JDouble fromRef(JObjectPtr ref) => JDouble.fromRef(ref); + + @override + JObjType get superType => const JNumberType(); + + @override + final superCount = 2; + + @override + int get hashCode => (JDoubleType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == JDoubleType && other is JDoubleType; + } +} + +class JDouble extends JNumber { + @override + // ignore: overridden_fields + late final JObjType $type = type; + + JDouble.fromRef( + JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = JDoubleType(); + + static final _class = Jni.findJClass(r"java/lang/Double"); + + static final _ctorId = + Jni.accessors.getMethodIDOf(_class.reference, r"", r"(D)V"); + JDouble(double num) + : super.fromRef(Jni.accessors + .newObjectWithArgs(_class.reference, _ctorId, [num]).object); +} diff --git a/pkgs/jni/lib/src/lang/jfloat.dart b/pkgs/jni/lib/src/lang/jfloat.dart new file mode 100644 index 000000000..a352659ea --- /dev/null +++ b/pkgs/jni/lib/src/lang/jfloat.dart @@ -0,0 +1,56 @@ +// Copyright (c) 2023, 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. + +import '../accessors.dart'; +import '../jni.dart'; +import '../jvalues.dart'; +import '../third_party/generated_bindings.dart'; +import '../types.dart'; +import 'jnumber.dart'; + +final class JFloatType extends JObjType { + const JFloatType(); + + @override + String get signature => r"Ljava/lang/Float;"; + + @override + JFloat fromRef(JObjectPtr ref) => JFloat.fromRef(ref); + + @override + JObjType get superType => const JNumberType(); + + @override + final superCount = 2; + + @override + int get hashCode => (JFloatType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == JFloatType && other is JFloatType; + } +} + +class JFloat extends JNumber { + @override + // ignore: overridden_fields + late final JObjType $type = type; + + JFloat.fromRef( + JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = JFloatType(); + + static final _class = Jni.findJClass(r"java/lang/Float"); + + static final _ctorId = + Jni.accessors.getMethodIDOf(_class.reference, r"", r"(F)V"); + + JFloat(double num) + : super.fromRef(Jni.accessors.newObjectWithArgs( + _class.reference, _ctorId, [JValueFloat(num)]).object); +} diff --git a/pkgs/jni/lib/src/lang/jinteger.dart b/pkgs/jni/lib/src/lang/jinteger.dart new file mode 100644 index 000000000..8ece46679 --- /dev/null +++ b/pkgs/jni/lib/src/lang/jinteger.dart @@ -0,0 +1,56 @@ +// Copyright (c) 2023, 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. + +import '../accessors.dart'; +import '../jni.dart'; +import '../jvalues.dart'; +import '../third_party/generated_bindings.dart'; +import '../types.dart'; +import 'jnumber.dart'; + +final class JIntegerType extends JObjType { + const JIntegerType(); + + @override + String get signature => r"Ljava/lang/Integer;"; + + @override + JInteger fromRef(JObjectPtr ref) => JInteger.fromRef(ref); + + @override + JObjType get superType => const JNumberType(); + + @override + final superCount = 2; + + @override + int get hashCode => (JIntegerType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == JIntegerType && other is JIntegerType; + } +} + +class JInteger extends JNumber { + @override + // ignore: overridden_fields + late final JObjType $type = type; + + JInteger.fromRef( + JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = JIntegerType(); + + static final _class = Jni.findJClass(r"java/lang/Integer"); + + static final _ctorId = + Jni.accessors.getMethodIDOf(_class.reference, r"", r"(I)V"); + + JInteger(int num) + : super.fromRef(Jni.accessors.newObjectWithArgs( + _class.reference, _ctorId, [JValueInt(num)]).object); +} diff --git a/pkgs/jni/lib/src/lang/jlong.dart b/pkgs/jni/lib/src/lang/jlong.dart new file mode 100644 index 000000000..66d054b98 --- /dev/null +++ b/pkgs/jni/lib/src/lang/jlong.dart @@ -0,0 +1,55 @@ +// Copyright (c) 2023, 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. + +import '../accessors.dart'; +import '../jni.dart'; +import '../third_party/generated_bindings.dart'; +import '../types.dart'; +import 'jnumber.dart'; + +final class JLongType extends JObjType { + const JLongType(); + + @override + String get signature => r"Ljava/lang/Long;"; + + @override + JLong fromRef(JObjectPtr ref) => JLong.fromRef(ref); + + @override + JObjType get superType => const JNumberType(); + + @override + final superCount = 2; + + @override + int get hashCode => (JLongType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == JLongType && other is JLongType; + } +} + +class JLong extends JNumber { + @override + // ignore: overridden_fields + late final JObjType $type = type; + + JLong.fromRef( + JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = JLongType(); + + static final _class = Jni.findJClass(r"java/lang/Long"); + + static final _ctorId = + Jni.accessors.getMethodIDOf(_class.reference, r"", r"(J)V"); + + JLong(int num) + : super.fromRef(Jni.accessors + .newObjectWithArgs(_class.reference, _ctorId, [num]).object); +} diff --git a/pkgs/jni/lib/src/lang/jnumber.dart b/pkgs/jni/lib/src/lang/jnumber.dart new file mode 100644 index 000000000..45d86dc0b --- /dev/null +++ b/pkgs/jni/lib/src/lang/jnumber.dart @@ -0,0 +1,158 @@ +// Copyright (c) 2023, 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. + +import '../accessors.dart'; +import '../jni.dart'; +import '../jobject.dart'; +import '../jreference.dart'; +import '../third_party/generated_bindings.dart'; +import '../types.dart'; +import 'jboolean.dart'; +import 'jbyte.dart'; +import 'jcharacter.dart'; +import 'jdouble.dart'; +import 'jfloat.dart'; +import 'jinteger.dart'; +import 'jlong.dart'; +import 'jshort.dart'; + +final class JNumberType extends JObjType { + const JNumberType(); + + @override + String get signature => r"Ljava/lang/Number;"; + + @override + JNumber fromRef(JObjectPtr ref) => JNumber.fromRef(ref); + + @override + JObjType get superType => const JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => (JNumberType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == JNumberType && other is JNumberType; + } +} + +class JNumber extends JObject { + @override + // ignore: overridden_fields + late final JObjType $type = type; + + JNumber.fromRef( + JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = Jni.findJClass(r"java/lang/Number"); + + /// The type which includes information such as the signature of this class. + static const type = JNumberType(); + static final _ctorId = + Jni.accessors.getMethodIDOf(_class.reference, r"", r"()V"); + + JNumber() + : super.fromRef(Jni.accessors + .newObjectWithArgs(_class.reference, _ctorId, []).object); + + static final _intValueId = + Jni.accessors.getMethodIDOf(_class.reference, r"intValue", r"()I"); + + int intValue({bool releaseOriginal = false}) { + ensureNotNull(); + final ret = Jni.accessors.callMethodWithArgs( + reference, _intValueId, JniCallType.intType, []).integer; + if (releaseOriginal) { + release(); + } + return ret; + } + + static final _longValueId = + Jni.accessors.getMethodIDOf(_class.reference, r"longValue", r"()J"); + + int longValue({bool releaseOriginal = false}) { + ensureNotNull(); + final ret = Jni.accessors.callMethodWithArgs( + reference, _longValueId, JniCallType.longType, []).long; + if (releaseOriginal) { + release(); + } + return ret; + } + + static final _floatValueId = + Jni.accessors.getMethodIDOf(_class.reference, r"floatValue", r"()F"); + + double floatValue({bool releaseOriginal = false}) { + ensureNotNull(); + final ret = Jni.accessors.callMethodWithArgs( + reference, _floatValueId, JniCallType.floatType, []).float; + if (releaseOriginal) { + release(); + } + return ret; + } + + static final _doubleValueId = + Jni.accessors.getMethodIDOf(_class.reference, r"doubleValue", r"()D"); + + double doubleValue({bool releaseOriginal = false}) { + ensureNotNull(); + final ret = Jni.accessors.callMethodWithArgs( + reference, _doubleValueId, JniCallType.doubleType, []).doubleFloat; + if (releaseOriginal) { + release(); + } + return ret; + } + + static final _byteValueId = + Jni.accessors.getMethodIDOf(_class.reference, r"byteValue", r"()B"); + + int byteValue({bool releaseOriginal = false}) { + ensureNotNull(); + final ret = Jni.accessors.callMethodWithArgs( + reference, _byteValueId, JniCallType.byteType, []).byte; + if (releaseOriginal) { + release(); + } + return ret; + } + + static final _shortValueId = + Jni.accessors.getMethodIDOf(_class.reference, r"shortValue", r"()S"); + + int shortValue({bool releaseOriginal = false}) { + ensureNotNull(); + final ret = Jni.accessors.callMethodWithArgs( + reference, _shortValueId, JniCallType.shortType, []).short; + if (releaseOriginal) { + release(); + } + return ret; + } +} + +extension IntToJava on int { + JByte toJByte() => JByte(this); + JShort toJShort() => JShort(this); + JInteger toJInteger() => JInteger(this); + JLong toJLong() => JLong(this); + JCharacter toJCharacter() => JCharacter(this); +} + +extension DoubleToJava on double { + JFloat toJFloat() => JFloat(this); + JDouble toJDouble() => JDouble(this); +} + +extension BoolToJava on bool { + JBoolean toJBoolean() => JBoolean(this); +} diff --git a/pkgs/jni/lib/src/lang/jshort.dart b/pkgs/jni/lib/src/lang/jshort.dart new file mode 100644 index 000000000..39d3c1d54 --- /dev/null +++ b/pkgs/jni/lib/src/lang/jshort.dart @@ -0,0 +1,56 @@ +// Copyright (c) 2023, 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. + +import '../accessors.dart'; +import '../jni.dart'; +import '../jvalues.dart'; +import '../third_party/generated_bindings.dart'; +import '../types.dart'; +import 'jnumber.dart'; + +final class JShortType extends JObjType { + const JShortType(); + + @override + String get signature => r"Ljava/lang/Short;"; + + @override + JShort fromRef(JObjectPtr ref) => JShort.fromRef(ref); + + @override + JObjType get superType => const JNumberType(); + + @override + final superCount = 2; + + @override + int get hashCode => (JShortType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == JShortType && other is JShortType; + } +} + +class JShort extends JNumber { + @override + // ignore: overridden_fields + late final JObjType $type = type; + + JShort.fromRef( + JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = JShortType(); + + static final _class = Jni.findJClass(r"java/lang/Short"); + + static final _ctorId = + Jni.accessors.getMethodIDOf(_class.reference, r"", r"(S)V"); + + JShort(int num) + : super.fromRef(Jni.accessors.newObjectWithArgs( + _class.reference, _ctorId, [JValueShort(num)]).object); +} diff --git a/pkgs/jni/lib/src/lang/jstring.dart b/pkgs/jni/lib/src/lang/jstring.dart new file mode 100644 index 000000000..9b8fbbb61 --- /dev/null +++ b/pkgs/jni/lib/src/lang/jstring.dart @@ -0,0 +1,74 @@ +// 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. + +import 'dart:ffi'; + +import 'package:jni/src/jreference.dart'; + +import '../jni.dart'; +import '../jobject.dart'; +import '../third_party/generated_bindings.dart'; +import '../types.dart'; + +final class JStringType extends JObjType { + const JStringType(); + + @override + String get signature => "Ljava/lang/String;"; + + @override + JString fromRef(Pointer ref) => JString.fromRef(ref); + + @override + JObjType get superType => const JObjectType(); + + @override + final int superCount = 1; + + @override + int get hashCode => (JStringType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == JStringType && other is JStringType; + } +} + +class JString extends JObject { + @override + // ignore: overridden_fields + late final JObjType $type = type; + + /// The type which includes information such as the signature of this class. + static const JObjType type = JStringType(); + + /// Construct a new [JString] with [reference] as its underlying reference. + JString.fromRef(JStringPtr reference) : super.fromRef(reference); + + /// The number of Unicode characters in this Java string. + int get length => Jni.env.GetStringLength(reference); + + /// Construct a [JString] from the contents of Dart string [s]. + JString.fromString(String s) : super.fromRef(Jni.env.toJStringPtr(s)); + + /// Returns the contents as a Dart String. + /// + /// If [releaseOriginal] is true, the underlying reference is deleted + /// after conversion and this object will be marked as released. + String toDartString({bool releaseOriginal = false}) { + ensureNotNull(); + final result = Jni.env.toDartString(reference); + if (releaseOriginal) { + release(); + } + return result; + } +} + +extension ToJStringMethod on String { + /// Returns a [JString] with the contents of this String. + JString toJString() { + return JString.fromString(this); + } +} diff --git a/pkgs/jni/lib/src/lang/lang.dart b/pkgs/jni/lib/src/lang/lang.dart new file mode 100644 index 000000000..786488c06 --- /dev/null +++ b/pkgs/jni/lib/src/lang/lang.dart @@ -0,0 +1,14 @@ +// Copyright (c) 2023, 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. + +export 'jboolean.dart'; +export 'jbyte.dart'; +export 'jcharacter.dart'; +export 'jdouble.dart'; +export 'jfloat.dart'; +export 'jinteger.dart'; +export 'jlong.dart'; +export 'jnumber.dart'; +export 'jshort.dart'; +export 'jstring.dart'; diff --git a/pkgs/jni/lib/src/method_invocation.dart b/pkgs/jni/lib/src/method_invocation.dart new file mode 100644 index 000000000..69cdc4a03 --- /dev/null +++ b/pkgs/jni/lib/src/method_invocation.dart @@ -0,0 +1,38 @@ +// Copyright (c) 2023, 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. + +import 'dart:ffi'; + +import 'third_party/generated_bindings.dart'; + +import 'lang/jstring.dart'; +import 'jarray.dart'; +import 'jobject.dart'; + +class $MethodInvocation { + final Pointer result; + final JString methodDescriptor; + final JArray args; + + $MethodInvocation._(this.result, this.methodDescriptor, this.args); + + factory $MethodInvocation.fromAddresses( + int resultAddress, + int descriptorAddress, + int argsAddress, + ) { + return $MethodInvocation._( + Pointer.fromAddress(resultAddress), + JString.fromRef(Pointer.fromAddress(descriptorAddress)), + JArray.fromRef( + const JObjectType(), + Pointer.fromAddress(argsAddress), + ), + ); + } + + factory $MethodInvocation.fromMessage(List message) { + return $MethodInvocation.fromAddresses(message[0], message[1], message[2]); + } +} diff --git a/pkgs/jni/lib/src/nio/jbuffer.dart b/pkgs/jni/lib/src/nio/jbuffer.dart new file mode 100644 index 000000000..cae6bc973 --- /dev/null +++ b/pkgs/jni/lib/src/nio/jbuffer.dart @@ -0,0 +1,255 @@ +// Copyright (c) 2023, 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. + +import '../accessors.dart'; +import '../jni.dart'; +import '../jobject.dart'; +import '../jvalues.dart'; +import '../third_party/generated_bindings.dart'; +import '../types.dart'; + +final class JBufferType extends JObjType { + const JBufferType(); + + @override + String get signature => r"Ljava/nio/Buffer;"; + + @override + JBuffer fromRef(JObjectPtr ref) => JBuffer.fromRef(ref); + + @override + JObjType get superType => const JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => (JBufferType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == (JBufferType) && other is JBufferType; + } +} + +/// A container for data of a specific primitive type. +/// +/// The bindings for `java.nio.Buffer`. +/// +/// A buffer is a linear, finite sequence of elements of a specific primitive +/// type. Aside from its content, the essential properties of a buffer are its +/// [capacity], [limit], and [position]. +/// +/// There is one subclass of this class for each non-boolean primitive type. +/// We currently only have the bindings for `java.nio.ByteBuffer` in this +/// package as [JByteBuffer]. +class JBuffer extends JObject { + @override + // ignore: overridden_fields + late final JObjType $type = type; + + JBuffer.fromRef( + JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = Jni.findJClass(r"java/nio/Buffer"); + + /// The type which includes information such as the signature of this class. + static const type = JBufferType(); + + static final _capacityId = + Jni.accessors.getMethodIDOf(_class.reference, r"capacity", r"()I"); + + /// The number of elements this buffer contains. + /// + /// It is never negative and never changes. + int get capacity { + return Jni.accessors.callMethodWithArgs( + reference, _capacityId, JniCallType.intType, []).integer; + } + + static final _positionId = + Jni.accessors.getMethodIDOf(_class.reference, r"position", r"()I"); + + /// The index of the next element to be read or written. + /// + /// It is never negative and is never greater than its [limit]. + int get position { + return Jni.accessors.callMethodWithArgs( + reference, _positionId, JniCallType.intType, []).integer; + } + + static final _setPositionId = Jni.accessors + .getMethodIDOf(_class.reference, r"position", r"(I)Ljava/nio/Buffer;"); + + /// Throws: + /// * [IllegalArgumentException] - If the preconditions on [newPosition] do + /// not hold. + set position(int position) { + Jni.env.DeleteGlobalRef(Jni.accessors.callMethodWithArgs(reference, + _setPositionId, JniCallType.objectType, [JValueInt(position)]).object); + } + + static final _limitId = + Jni.accessors.getMethodIDOf(_class.reference, r"limit", r"()I"); + + /// The index of the first element that should not be read or written. + /// + /// It is never negative and is never greater than its [capacity]. + int get limit { + return Jni.accessors.callMethodWithArgs( + reference, _limitId, JniCallType.intType, []).integer; + } + + static final _setLimitId = Jni.accessors + .getMethodIDOf(_class.reference, r"limit", r"(I)Ljava/nio/Buffer;"); + + /// Throws: + /// * [IllegalArgumentException] - If the preconditions on [newLimit] do not + /// hold. + set limit(int newLimit) { + Jni.env.DeleteGlobalRef(Jni.accessors.callMethodWithArgs(reference, + _setLimitId, JniCallType.objectType, [JValueInt(newLimit)]).object); + } + + static final _markId = Jni.accessors + .getMethodIDOf(_class.reference, r"mark", r"()Ljava/nio/Buffer;"); + + /// Sets this buffer's mark at its [position]. + /// + /// Mark is the index to which its [position] will be reset when the [reset] + /// method is invoked. + void mark() { + Jni.env.DeleteGlobalRef(Jni.accessors.callMethodWithArgs( + reference, _markId, JniCallType.objectType, []).object); + } + + static final _resetId = Jni.accessors + .getMethodIDOf(_class.reference, r"reset", r"()Ljava/nio/Buffer;"); + + /// Resets this buffer's [position] to the previously-marked position. + /// + /// Throws: + /// * [InvalidMarkException] - If the mark has not been set + void reset() { + Jni.env.DeleteGlobalRef(Jni.accessors.callMethodWithArgs( + reference, _resetId, JniCallType.objectType, []).object); + } + + static final _clearId = Jni.accessors + .getMethodIDOf(_class.reference, r"clear", r"()Ljava/nio/Buffer;"); + + /// Clears this buffer. + /// + /// The [position] is set to zero, the [limit] is set to + /// the [capacity], and the mark is discarded. + void clear() { + Jni.env.DeleteGlobalRef(Jni.accessors.callMethodWithArgs( + reference, _clearId, JniCallType.objectType, []).object); + } + + static final _flipId = Jni.accessors + .getMethodIDOf(_class.reference, r"flip", r"()Ljava/nio/Buffer;"); + + /// Flips this buffer. + /// + /// The limit is set to the current [position] and then the [position] is set + /// to zero. If the mark is defined then it is discarded. + void flip() { + Jni.env.DeleteGlobalRef(Jni.accessors.callMethodWithArgs( + reference, _flipId, JniCallType.objectType, []).object); + } + + static final _rewindId = Jni.accessors + .getMethodIDOf(_class.reference, r"rewind", r"()Ljava/nio/Buffer;"); + + /// Rewinds this buffer. + /// + /// The [position] is set to zero and the mark is discarded. + void rewind() { + Jni.env.DeleteGlobalRef(Jni.accessors.callMethodWithArgs( + reference, _rewindId, JniCallType.objectType, []).object); + } + + static final _remainingId = + Jni.accessors.getMethodIDOf(_class.reference, r"remaining", r"()I"); + + /// The number of elements between the current [position] and the + /// [limit]. + int get remaining { + return Jni.accessors.callMethodWithArgs( + reference, _remainingId, JniCallType.intType, []).integer; + } + + static final _hasRemainingId = + Jni.accessors.getMethodIDOf(_class.reference, r"hasRemaining", r"()Z"); + + /// Whether there are any elements between the current [position] and + /// the [limit]. + bool get hasRemaining { + return Jni.accessors.callMethodWithArgs( + reference, _hasRemainingId, JniCallType.booleanType, []).boolean; + } + + static final _isReadOnlyId = + Jni.accessors.getMethodIDOf(_class.reference, r"isReadOnly", r"()Z"); + + /// Whether or not this buffer is read-only. + bool get isReadOnly { + return Jni.accessors.callMethodWithArgs( + reference, _isReadOnlyId, JniCallType.booleanType, []).boolean; + } + + static final _hasArrayId = + Jni.accessors.getMethodIDOf(_class.reference, r"hasArray", r"()Z"); + + /// Whether or not this buffer is backed by an accessible array. + bool get hasArray { + return Jni.accessors.callMethodWithArgs( + reference, _hasArrayId, JniCallType.booleanType, []).boolean; + } + + static final _arrayId = Jni.accessors + .getMethodIDOf(_class.reference, r"array", r"()Ljava/lang/Object;"); + + /// The array that backs this buffer. + /// + /// Concrete subclasses like [JByteBuffer] provide more strongly-typed return + /// values for this method. + /// + /// Throws: + /// * [ReadOnlyBufferException] - If this buffer is backed by an array but is + /// read-only + /// * [UnsupportedOperationException] - If this buffer is not backed by an + /// accessible array + JObject get array { + return const JObjectType().fromRef(Jni.accessors.callMethodWithArgs( + reference, _arrayId, JniCallType.objectType, []).object); + } + + static final _arrayOffsetId = + Jni.accessors.getMethodIDOf(_class.reference, r"arrayOffset", r"()I"); + + /// The offset within this buffer's backing array of the first element + /// of the buffer. + /// + /// Throws: + /// * [ReadOnlyBufferException] - If this buffer is backed by an array but is + /// read-only + /// * [UnsupportedOperationException] - If this buffer is not backed by an + /// accessible array + int get arrayOffset { + return Jni.accessors.callMethodWithArgs( + reference, _arrayOffsetId, JniCallType.intType, []).integer; + } + + static final _isDirectId = + Jni.accessors.getMethodIDOf(_class.reference, r"isDirect", r"()Z"); + + /// Whether or not this buffer is direct. + bool get isDirect { + return Jni.accessors.callMethodWithArgs( + reference, _isDirectId, JniCallType.booleanType, []).boolean; + } +} diff --git a/pkgs/jni/lib/src/nio/jbyte_buffer.dart b/pkgs/jni/lib/src/nio/jbyte_buffer.dart new file mode 100644 index 000000000..d5f548851 --- /dev/null +++ b/pkgs/jni/lib/src/nio/jbyte_buffer.dart @@ -0,0 +1,315 @@ +// Copyright (c) 2023, 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. + +import 'dart:ffi'; +import 'dart:typed_data'; + +import '../accessors.dart'; +import '../jarray.dart'; +import '../jni.dart'; +import '../jreference.dart'; +import '../jvalues.dart'; +import '../third_party/generated_bindings.dart'; +import '../types.dart'; +import 'jbuffer.dart'; + +final class JByteBufferType extends JObjType { + const JByteBufferType(); + + @override + String get signature => r"Ljava/nio/ByteBuffer;"; + + @override + JByteBuffer fromRef(JObjectPtr ref) => JByteBuffer.fromRef(ref); + + @override + JObjType get superType => const JBufferType(); + + @override + final superCount = 2; + + @override + int get hashCode => (JByteBufferType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == (JByteBufferType) && other is JByteBufferType; + } +} + +/// A byte [JBuffer]. +/// +/// The bindings for `java.nio.ByteBuffer`. +/// +/// This enables fast memory copying between Java and Dart when directly +/// allocated (See [JByteBuffer.allocateDirect]). +/// +/// To create a [JByteBuffer] from the content of a [Uint8List], +/// use [JByteBuffer.fromList]. This uses direct allocation to enable fast +/// copying. +/// +/// [asUint8List] provides a direct access to the underlying [Uint8List] that +/// this buffer uses. This means any changes to it will change the content of +/// the buffer and vice versa. This can be used to access to [Uint8List] methods +/// such as [Uint8List.setRange]. +/// +/// Example: +/// ```dart +/// final directBuffer = JByteBuffer.allocateDirect(3); +/// directBuffer.asUint8List().setAll(0, [1, 2, 3]); +/// // The buffer is now 1, 2, 3. +/// ``` +/// +/// Both the original buffer and the [Uint8List] keep the underlying Java buffer +/// alive. Once all the instances of the original buffer and the lists produced +/// from [asUint8List] are inaccessible both in Java and Dart, Java will +/// correctly garbage collects the buffer and frees its underlying memory. +/// +/// Example: +/// ```dart +/// final directBuffer = JByteBuffer.allocateDirect(3); +/// final data = directBuffer.asUint8List(); +/// directBuffer.release(); // Releasing the original buffer. +/// data.setAll(0, [1, 2, 3]); // Works! [data] is still accessible. +/// ``` +/// +/// The original buffer can be [release]d when calling [asUint8List] +/// by setting the `releaseOriginal` parameter to `true`. +/// +/// Example: +/// ```dart +/// final directBuffer = JByteBuffer.allocateDirect(3); +/// // [releaseOriginal] is `false` by default. +/// final data1 = directBuffer.asUint8List(); +/// directBuffer.nextByte = 42; // No problem! +/// print(data1[0]); // prints 42! +/// final data2 = directBuffer.asUint8List(releaseOriginal: true); +/// // directBuffer.nextByte = 42; // throws [UseAfterReleaseException]! +/// ``` +class JByteBuffer extends JBuffer { + @override + // ignore: overridden_fields + late final JObjType $type = type; + + JByteBuffer.fromRef( + JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = Jni.findJClass(r"java/nio/ByteBuffer"); + + /// The type which includes information such as the signature of this class. + static const type = JByteBufferType(); + + static final _allocateDirectId = Jni.accessors.getStaticMethodIDOf( + _class.reference, r"allocateDirect", r"(I)Ljava/nio/ByteBuffer;"); + + /// Allocates a new direct byte buffer. + /// + /// Throws: + /// * [IllegalArgumentException] - If the capacity is a negative integer + factory JByteBuffer.allocateDirect(int capacity) { + return JByteBuffer.fromRef( + Jni.accessors.callStaticMethodWithArgs( + _class.reference, + _allocateDirectId, + JniCallType.objectType, + [JValueInt(capacity)]).object, + ); + } + + static final _allocateId = Jni.accessors.getStaticMethodIDOf( + _class.reference, r"allocate", r"(I)Ljava/nio/ByteBuffer;"); + + /// Allocates a new byte buffer. + /// + /// Throws: + /// * [IllegalArgumentException] - If the capacity is a negative integer + factory JByteBuffer.allocate(int capacity) { + return const JByteBufferType().fromRef(Jni.accessors + .callStaticMethodWithArgs(_class.reference, _allocateId, + JniCallType.objectType, [JValueInt(capacity)]).object); + } + + static final _wrapWholeId = Jni.accessors.getStaticMethodIDOf( + _class.reference, r"wrap", r"([B)Ljava/nio/ByteBuffer;"); + static final _wrapId = Jni.accessors.getStaticMethodIDOf( + _class.reference, r"wrap", r"([BII)Ljava/nio/ByteBuffer;"); + + /// Wraps a byte array into a buffer. + /// + /// The new buffer will be backed by the given byte array; that is, + /// modifications to the buffer will cause the array to be modified + /// and vice versa. + static JByteBuffer wrap( + JArray array, [ + int? offset, + int? length, + ]) { + if (offset == null && length == null) { + return const JByteBufferType().fromRef( + Jni.accessors.callStaticMethodWithArgs( + _class.reference, + _wrapWholeId, + JniCallType.objectType, + [array.reference], + ).object, + ); + } + offset ??= 0; + length ??= array.length - offset; + return const JByteBufferType().fromRef( + Jni.accessors.callStaticMethodWithArgs( + _class.reference, + _wrapId, + JniCallType.objectType, + [array.reference, JValueInt(offset), JValueInt(length)], + ).object, + ); + } + + /// Creates a [JByteBuffer] from the content of [list]. + /// + /// The [JByteBuffer] will be allocated using [JByteBuffer.allocateDirect]. + factory JByteBuffer.fromList(Uint8List list) { + final buffer = JByteBuffer.allocateDirect(list.length); + buffer._asUint8ListUnsafe().setAll(0, list); + return buffer; + } + + static final _sliceId = Jni.accessors + .getMethodIDOf(_class.reference, r"slice", r"()Ljava/nio/ByteBuffer;"); + + /// Creates a new byte buffer whose content is a shared subsequence of this + /// buffer's content. + JByteBuffer slice() { + return const JByteBufferType().fromRef(Jni.accessors.callMethodWithArgs( + reference, _sliceId, JniCallType.objectType, []).object); + } + + static final _duplicateId = Jni.accessors.getMethodIDOf( + _class.reference, r"duplicate", r"()Ljava/nio/ByteBuffer;"); + + /// Creates a new byte buffer that shares this buffer's content. + JByteBuffer duplicate() { + return const JByteBufferType().fromRef(Jni.accessors.callMethodWithArgs( + reference, _duplicateId, JniCallType.objectType, []).object); + } + + static final _asReadOnlyBufferId = Jni.accessors.getMethodIDOf( + _class.reference, r"asReadOnlyBuffer", r"()Ljava/nio/ByteBuffer;"); + + /// Creates a new, read-only byte buffer that shares this buffer's content. + JByteBuffer asReadOnlyBuffer() { + return const JByteBufferType().fromRef(Jni.accessors.callMethodWithArgs( + reference, _asReadOnlyBufferId, JniCallType.objectType, []).object); + } + + static final _getId = + Jni.accessors.getMethodIDOf(_class.reference, r"get", r"()B"); + + /// Reads the byte at this buffer's current [position], and then increments the + /// [position]. + /// + /// Throws: + /// * [BufferOverflowException] - If the buffer's current [position] is not + /// smaller than its [limit] + int get nextByte { + return Jni.accessors + .callMethodWithArgs(reference, _getId, JniCallType.byteType, []).byte; + } + + static final _putId = Jni.accessors + .getMethodIDOf(_class.reference, r"put", r"(B)Ljava/nio/ByteBuffer;"); + + /// Writes the given byte into this buffer at the current [position], and then + /// increments the [position]. + /// + /// Throws: + /// * [BufferOverflowException] - If this buffer's current [position] is not + /// smaller than its [limit] + /// * [ReadOnlyBufferException] - If this buffer is read-only + set nextByte(int b) { + Jni.env.DeleteGlobalRef(Jni.accessors.callMethodWithArgs( + reference, _putId, JniCallType.objectType, [JValueByte(b)]).object); + } + + static final _arrayId = + Jni.accessors.getMethodIDOf(_class.reference, r"array", r"()[B"); + + @override + JArray get array { + return const JArrayType(jbyteType()).fromRef(Jni.accessors + .callMethodWithArgs( + reference, _arrayId, JniCallType.objectType, []).object); + } + + void _ensureIsDirect() { + if (!isDirect) { + throw StateError( + 'The buffer must be created with `JByteBuffer.allocateDirect`.', + ); + } + } + + Pointer _directBufferAddress() { + final address = Jni.env.GetDirectBufferAddress(reference); + if (address == nullptr) { + throw StateError( + 'The memory region is undefined or ' + 'direct buffer access is not supported by this JVM.', + ); + } + return address; + } + + int _directBufferCapacity() { + final capacity = Jni.env.GetDirectBufferCapacity(reference); + if (capacity == -1) { + throw StateError( + 'The object is an unaligned view buffer and the processor ' + 'architecture does not support unaligned access.', + ); + } + return capacity; + } + + Uint8List _asUint8ListUnsafe() { + _ensureIsDirect(); + final address = _directBufferAddress(); + final capacity = _directBufferCapacity(); + return address.cast().asTypedList(capacity); + } + + /// Returns this byte buffer as a [Uint8List]. + /// + /// If [releaseOriginal] is `true`, this byte buffer will be released. + /// + /// Throws [StateError] if the buffer is not direct + /// (see [JByteBuffer.allocateDirect]) or the JVM does not support the direct + /// buffer operations or the object is an unaligned view buffer and + /// the processor does not support unaligned access. + Uint8List asUint8List({bool releaseOriginal = false}) { + _ensureIsDirect(); + final address = _directBufferAddress(); + final capacity = _directBufferCapacity(); + final token = releaseOriginal ? reference : Jni.env.NewGlobalRef(reference); + if (releaseOriginal) { + setAsReleased(); + } + return address.cast().asTypedList( + capacity, + token: token, + finalizer: Jni.env.ptr.ref.DeleteGlobalRef.cast(), + ); + } +} + +extension Uint8ListToJava on Uint8List { + /// Creates a [JByteBuffer] from the content of this list. + /// + /// The [JByteBuffer] will be allocated using [JByteBuffer.allocateDirect]. + JByteBuffer toJByteBuffer() { + return JByteBuffer.fromList(this); + } +} diff --git a/pkgs/jni/lib/src/nio/nio.dart b/pkgs/jni/lib/src/nio/nio.dart new file mode 100644 index 000000000..3092870fa --- /dev/null +++ b/pkgs/jni/lib/src/nio/nio.dart @@ -0,0 +1,6 @@ +// Copyright (c) 2023, 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. + +export 'jbuffer.dart'; +export 'jbyte_buffer.dart'; diff --git a/pkgs/jni/lib/src/third_party/generated_bindings.dart b/pkgs/jni/lib/src/third_party/generated_bindings.dart new file mode 100644 index 000000000..6047975b9 --- /dev/null +++ b/pkgs/jni/lib/src/third_party/generated_bindings.dart @@ -0,0 +1,2 @@ +export 'jni_bindings_generated.dart'; +export 'global_env_extensions.dart'; diff --git a/pkgs/jni/lib/src/third_party/global_env_extensions.dart b/pkgs/jni/lib/src/third_party/global_env_extensions.dart new file mode 100644 index 000000000..2fe400109 --- /dev/null +++ b/pkgs/jni/lib/src/third_party/global_env_extensions.dart @@ -0,0 +1,1514 @@ +// Auto generated file. Do not edit. + +// This is generated from JNI header in Android NDK. License for the same is +// provided below. + +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * JNI specification, as defined by Sun: + * http://java.sun.com/javase/6/docs/technotes/guides/jni/spec/jniTOC.html + * + * Everything here is expected to be VM-neutral. + */ + +// ignore_for_file: non_constant_identifier_names +// coverage:ignore-file + +import "dart:ffi" as ffi; + +import "jni_bindings_generated.dart"; + +import "../accessors.dart"; + +/// Wraps over Pointer and exposes function pointer fields +/// as methods. +class GlobalJniEnv { + final ffi.Pointer ptr; + GlobalJniEnv(this.ptr); + late final _GetVersion = + ptr.ref.GetVersion.asFunction(); + + int GetVersion() => _GetVersion().integer; + + late final _DefineClass = ptr.ref.DefineClass.asFunction< + JniClassLookupResult Function(ffi.Pointer name, + JObjectPtr loader, ffi.Pointer buf, int bufLen)>(); + + JClassPtr DefineClass(ffi.Pointer name, JObjectPtr loader, + ffi.Pointer buf, int bufLen) => + _DefineClass(name, loader, buf, bufLen).value; + + late final _FindClass = ptr.ref.FindClass + .asFunction name)>(); + + JClassPtr FindClass(ffi.Pointer name) => _FindClass(name).value; + + late final _FromReflectedMethod = ptr.ref.FromReflectedMethod + .asFunction(); + + JMethodIDPtr FromReflectedMethod(JObjectPtr method) => + _FromReflectedMethod(method).methodID; + + late final _FromReflectedField = ptr.ref.FromReflectedField + .asFunction(); + + JFieldIDPtr FromReflectedField(JObjectPtr field) => + _FromReflectedField(field).fieldID; + + late final _ToReflectedMethod = ptr.ref.ToReflectedMethod.asFunction< + JniResult Function(JClassPtr cls, JMethodIDPtr methodId, int isStatic)>(); + + JObjectPtr ToReflectedMethod( + JClassPtr cls, JMethodIDPtr methodId, int isStatic) => + _ToReflectedMethod(cls, methodId, isStatic).object; + + late final _GetSuperclass = ptr.ref.GetSuperclass + .asFunction(); + + JClassPtr GetSuperclass(JClassPtr clazz) => _GetSuperclass(clazz).value; + + late final _IsAssignableFrom = ptr.ref.IsAssignableFrom + .asFunction(); + + bool IsAssignableFrom(JClassPtr clazz1, JClassPtr clazz2) => + _IsAssignableFrom(clazz1, clazz2).boolean; + + late final _ToReflectedField = ptr.ref.ToReflectedField.asFunction< + JniResult Function(JClassPtr cls, JFieldIDPtr fieldID, int isStatic)>(); + + JObjectPtr ToReflectedField( + JClassPtr cls, JFieldIDPtr fieldID, int isStatic) => + _ToReflectedField(cls, fieldID, isStatic).object; + + late final _Throw = + ptr.ref.Throw.asFunction(); + + int Throw(JThrowablePtr obj) => _Throw(obj).integer; + + late final _ThrowNew = ptr.ref.ThrowNew.asFunction< + JniResult Function(JClassPtr clazz, ffi.Pointer message)>(); + + int ThrowNew(JClassPtr clazz, ffi.Pointer message) => + _ThrowNew(clazz, message).integer; + + late final _ExceptionOccurred = + ptr.ref.ExceptionOccurred.asFunction(); + + JThrowablePtr ExceptionOccurred() => _ExceptionOccurred().object; + + late final _ExceptionDescribe = + ptr.ref.ExceptionDescribe.asFunction(); + + void ExceptionDescribe() => _ExceptionDescribe().check(); + + late final _ExceptionClear = + ptr.ref.ExceptionClear.asFunction(); + + void ExceptionClear() => _ExceptionClear().check(); + + late final _FatalError = ptr.ref.FatalError + .asFunction msg)>(); + + void FatalError(ffi.Pointer msg) => _FatalError(msg).check(); + + late final _PushLocalFrame = + ptr.ref.PushLocalFrame.asFunction(); + + int PushLocalFrame(int capacity) => _PushLocalFrame(capacity).integer; + + late final _PopLocalFrame = + ptr.ref.PopLocalFrame.asFunction(); + + JObjectPtr PopLocalFrame(JObjectPtr result) => _PopLocalFrame(result).object; + + late final _NewGlobalRef = + ptr.ref.NewGlobalRef.asFunction(); + + JObjectPtr NewGlobalRef(JObjectPtr obj) => _NewGlobalRef(obj).object; + + late final _DeleteGlobalRef = ptr.ref.DeleteGlobalRef + .asFunction(); + + void DeleteGlobalRef(JObjectPtr globalRef) => + _DeleteGlobalRef(globalRef).check(); + + late final _DeleteLocalRef = ptr.ref.DeleteLocalRef + .asFunction(); + + void DeleteLocalRef(JObjectPtr localRef) => _DeleteLocalRef(localRef).check(); + + late final _IsSameObject = ptr.ref.IsSameObject + .asFunction(); + + bool IsSameObject(JObjectPtr ref1, JObjectPtr ref2) => + _IsSameObject(ref1, ref2).boolean; + + late final _NewLocalRef = + ptr.ref.NewLocalRef.asFunction(); + + JObjectPtr NewLocalRef(JObjectPtr obj) => _NewLocalRef(obj).object; + + late final _EnsureLocalCapacity = ptr.ref.EnsureLocalCapacity + .asFunction(); + + int EnsureLocalCapacity(int capacity) => + _EnsureLocalCapacity(capacity).integer; + + late final _AllocObject = + ptr.ref.AllocObject.asFunction(); + + JObjectPtr AllocObject(JClassPtr clazz) => _AllocObject(clazz).object; + + late final _NewObject = ptr.ref.NewObject + .asFunction(); + + JObjectPtr NewObject(JClassPtr clazz, JMethodIDPtr methodID) => + _NewObject(clazz, methodID).object; + + late final _NewObjectA = ptr.ref.NewObjectA.asFunction< + JniResult Function( + JClassPtr clazz, JMethodIDPtr methodID, ffi.Pointer args)>(); + + JObjectPtr NewObjectA( + JClassPtr clazz, JMethodIDPtr methodID, ffi.Pointer args) => + _NewObjectA(clazz, methodID, args).object; + + late final _GetObjectClass = ptr.ref.GetObjectClass + .asFunction(); + + JClassPtr GetObjectClass(JObjectPtr obj) => _GetObjectClass(obj).value; + + late final _IsInstanceOf = ptr.ref.IsInstanceOf + .asFunction(); + + bool IsInstanceOf(JObjectPtr obj, JClassPtr clazz) => + _IsInstanceOf(obj, clazz).boolean; + + late final _GetMethodID = ptr.ref.GetMethodID.asFunction< + JniPointerResult Function(JClassPtr clazz, ffi.Pointer name, + ffi.Pointer sig)>(); + + JMethodIDPtr GetMethodID(JClassPtr clazz, ffi.Pointer name, + ffi.Pointer sig) => + _GetMethodID(clazz, name, sig).methodID; + + late final _CallObjectMethod = ptr.ref.CallObjectMethod + .asFunction(); + + JObjectPtr CallObjectMethod(JObjectPtr obj, JMethodIDPtr methodID) => + _CallObjectMethod(obj, methodID).object; + + late final _CallObjectMethodA = ptr.ref.CallObjectMethodA.asFunction< + JniResult Function( + JObjectPtr obj, JMethodIDPtr methodID, ffi.Pointer args)>(); + + JObjectPtr CallObjectMethodA( + JObjectPtr obj, JMethodIDPtr methodID, ffi.Pointer args) => + _CallObjectMethodA(obj, methodID, args).object; + + late final _CallBooleanMethod = ptr.ref.CallBooleanMethod + .asFunction(); + + bool CallBooleanMethod(JObjectPtr obj, JMethodIDPtr methodID) => + _CallBooleanMethod(obj, methodID).boolean; + + late final _CallBooleanMethodA = ptr.ref.CallBooleanMethodA.asFunction< + JniResult Function( + JObjectPtr obj, JMethodIDPtr methodId, ffi.Pointer args)>(); + + bool CallBooleanMethodA( + JObjectPtr obj, JMethodIDPtr methodId, ffi.Pointer args) => + _CallBooleanMethodA(obj, methodId, args).boolean; + + late final _CallByteMethod = ptr.ref.CallByteMethod + .asFunction(); + + int CallByteMethod(JObjectPtr obj, JMethodIDPtr methodID) => + _CallByteMethod(obj, methodID).byte; + + late final _CallByteMethodA = ptr.ref.CallByteMethodA.asFunction< + JniResult Function( + JObjectPtr obj, JMethodIDPtr methodID, ffi.Pointer args)>(); + + int CallByteMethodA( + JObjectPtr obj, JMethodIDPtr methodID, ffi.Pointer args) => + _CallByteMethodA(obj, methodID, args).byte; + + late final _CallCharMethod = ptr.ref.CallCharMethod + .asFunction(); + + int CallCharMethod(JObjectPtr obj, JMethodIDPtr methodID) => + _CallCharMethod(obj, methodID).char; + + late final _CallCharMethodA = ptr.ref.CallCharMethodA.asFunction< + JniResult Function( + JObjectPtr obj, JMethodIDPtr methodID, ffi.Pointer args)>(); + + int CallCharMethodA( + JObjectPtr obj, JMethodIDPtr methodID, ffi.Pointer args) => + _CallCharMethodA(obj, methodID, args).char; + + late final _CallShortMethod = ptr.ref.CallShortMethod + .asFunction(); + + int CallShortMethod(JObjectPtr obj, JMethodIDPtr methodID) => + _CallShortMethod(obj, methodID).short; + + late final _CallShortMethodA = ptr.ref.CallShortMethodA.asFunction< + JniResult Function( + JObjectPtr obj, JMethodIDPtr methodID, ffi.Pointer args)>(); + + int CallShortMethodA( + JObjectPtr obj, JMethodIDPtr methodID, ffi.Pointer args) => + _CallShortMethodA(obj, methodID, args).short; + + late final _CallIntMethod = ptr.ref.CallIntMethod + .asFunction(); + + int CallIntMethod(JObjectPtr obj, JMethodIDPtr methodID) => + _CallIntMethod(obj, methodID).integer; + + late final _CallIntMethodA = ptr.ref.CallIntMethodA.asFunction< + JniResult Function( + JObjectPtr obj, JMethodIDPtr methodID, ffi.Pointer args)>(); + + int CallIntMethodA( + JObjectPtr obj, JMethodIDPtr methodID, ffi.Pointer args) => + _CallIntMethodA(obj, methodID, args).integer; + + late final _CallLongMethod = ptr.ref.CallLongMethod + .asFunction(); + + int CallLongMethod(JObjectPtr obj, JMethodIDPtr methodID) => + _CallLongMethod(obj, methodID).long; + + late final _CallLongMethodA = ptr.ref.CallLongMethodA.asFunction< + JniResult Function( + JObjectPtr obj, JMethodIDPtr methodID, ffi.Pointer args)>(); + + int CallLongMethodA( + JObjectPtr obj, JMethodIDPtr methodID, ffi.Pointer args) => + _CallLongMethodA(obj, methodID, args).long; + + late final _CallFloatMethod = ptr.ref.CallFloatMethod + .asFunction(); + + double CallFloatMethod(JObjectPtr obj, JMethodIDPtr methodID) => + _CallFloatMethod(obj, methodID).float; + + late final _CallFloatMethodA = ptr.ref.CallFloatMethodA.asFunction< + JniResult Function( + JObjectPtr obj, JMethodIDPtr methodID, ffi.Pointer args)>(); + + double CallFloatMethodA( + JObjectPtr obj, JMethodIDPtr methodID, ffi.Pointer args) => + _CallFloatMethodA(obj, methodID, args).float; + + late final _CallDoubleMethod = ptr.ref.CallDoubleMethod + .asFunction(); + + double CallDoubleMethod(JObjectPtr obj, JMethodIDPtr methodID) => + _CallDoubleMethod(obj, methodID).doubleFloat; + + late final _CallDoubleMethodA = ptr.ref.CallDoubleMethodA.asFunction< + JniResult Function( + JObjectPtr obj, JMethodIDPtr methodID, ffi.Pointer args)>(); + + double CallDoubleMethodA( + JObjectPtr obj, JMethodIDPtr methodID, ffi.Pointer args) => + _CallDoubleMethodA(obj, methodID, args).doubleFloat; + + late final _CallVoidMethod = ptr.ref.CallVoidMethod.asFunction< + JThrowablePtr Function(JObjectPtr obj, JMethodIDPtr methodID)>(); + + void CallVoidMethod(JObjectPtr obj, JMethodIDPtr methodID) => + _CallVoidMethod(obj, methodID).check(); + + late final _CallVoidMethodA = ptr.ref.CallVoidMethodA.asFunction< + JThrowablePtr Function( + JObjectPtr obj, JMethodIDPtr methodID, ffi.Pointer args)>(); + + void CallVoidMethodA( + JObjectPtr obj, JMethodIDPtr methodID, ffi.Pointer args) => + _CallVoidMethodA(obj, methodID, args).check(); + + late final _CallNonvirtualObjectMethod = ptr.ref.CallNonvirtualObjectMethod + .asFunction< + JniResult Function( + JObjectPtr obj, JClassPtr clazz, JMethodIDPtr methodID)>(); + + JObjectPtr CallNonvirtualObjectMethod( + JObjectPtr obj, JClassPtr clazz, JMethodIDPtr methodID) => + _CallNonvirtualObjectMethod(obj, clazz, methodID).object; + + late final _CallNonvirtualObjectMethodA = ptr.ref.CallNonvirtualObjectMethodA + .asFunction< + JniResult Function(JObjectPtr obj, JClassPtr clazz, + JMethodIDPtr methodID, ffi.Pointer args)>(); + + JObjectPtr CallNonvirtualObjectMethodA(JObjectPtr obj, JClassPtr clazz, + JMethodIDPtr methodID, ffi.Pointer args) => + _CallNonvirtualObjectMethodA(obj, clazz, methodID, args).object; + + late final _CallNonvirtualBooleanMethod = ptr.ref.CallNonvirtualBooleanMethod + .asFunction< + JniResult Function( + JObjectPtr obj, JClassPtr clazz, JMethodIDPtr methodID)>(); + + bool CallNonvirtualBooleanMethod( + JObjectPtr obj, JClassPtr clazz, JMethodIDPtr methodID) => + _CallNonvirtualBooleanMethod(obj, clazz, methodID).boolean; + + late final _CallNonvirtualBooleanMethodA = + ptr.ref.CallNonvirtualBooleanMethodA.asFunction< + JniResult Function(JObjectPtr obj, JClassPtr clazz, + JMethodIDPtr methodID, ffi.Pointer args)>(); + + bool CallNonvirtualBooleanMethodA(JObjectPtr obj, JClassPtr clazz, + JMethodIDPtr methodID, ffi.Pointer args) => + _CallNonvirtualBooleanMethodA(obj, clazz, methodID, args).boolean; + + late final _CallNonvirtualByteMethod = ptr.ref.CallNonvirtualByteMethod + .asFunction< + JniResult Function( + JObjectPtr obj, JClassPtr clazz, JMethodIDPtr methodID)>(); + + int CallNonvirtualByteMethod( + JObjectPtr obj, JClassPtr clazz, JMethodIDPtr methodID) => + _CallNonvirtualByteMethod(obj, clazz, methodID).byte; + + late final _CallNonvirtualByteMethodA = ptr.ref.CallNonvirtualByteMethodA + .asFunction< + JniResult Function(JObjectPtr obj, JClassPtr clazz, + JMethodIDPtr methodID, ffi.Pointer args)>(); + + int CallNonvirtualByteMethodA(JObjectPtr obj, JClassPtr clazz, + JMethodIDPtr methodID, ffi.Pointer args) => + _CallNonvirtualByteMethodA(obj, clazz, methodID, args).byte; + + late final _CallNonvirtualCharMethod = ptr.ref.CallNonvirtualCharMethod + .asFunction< + JniResult Function( + JObjectPtr obj, JClassPtr clazz, JMethodIDPtr methodID)>(); + + int CallNonvirtualCharMethod( + JObjectPtr obj, JClassPtr clazz, JMethodIDPtr methodID) => + _CallNonvirtualCharMethod(obj, clazz, methodID).char; + + late final _CallNonvirtualCharMethodA = ptr.ref.CallNonvirtualCharMethodA + .asFunction< + JniResult Function(JObjectPtr obj, JClassPtr clazz, + JMethodIDPtr methodID, ffi.Pointer args)>(); + + int CallNonvirtualCharMethodA(JObjectPtr obj, JClassPtr clazz, + JMethodIDPtr methodID, ffi.Pointer args) => + _CallNonvirtualCharMethodA(obj, clazz, methodID, args).char; + + late final _CallNonvirtualShortMethod = ptr.ref.CallNonvirtualShortMethod + .asFunction< + JniResult Function( + JObjectPtr obj, JClassPtr clazz, JMethodIDPtr methodID)>(); + + int CallNonvirtualShortMethod( + JObjectPtr obj, JClassPtr clazz, JMethodIDPtr methodID) => + _CallNonvirtualShortMethod(obj, clazz, methodID).short; + + late final _CallNonvirtualShortMethodA = ptr.ref.CallNonvirtualShortMethodA + .asFunction< + JniResult Function(JObjectPtr obj, JClassPtr clazz, + JMethodIDPtr methodID, ffi.Pointer args)>(); + + int CallNonvirtualShortMethodA(JObjectPtr obj, JClassPtr clazz, + JMethodIDPtr methodID, ffi.Pointer args) => + _CallNonvirtualShortMethodA(obj, clazz, methodID, args).short; + + late final _CallNonvirtualIntMethod = ptr.ref.CallNonvirtualIntMethod + .asFunction< + JniResult Function( + JObjectPtr obj, JClassPtr clazz, JMethodIDPtr methodID)>(); + + int CallNonvirtualIntMethod( + JObjectPtr obj, JClassPtr clazz, JMethodIDPtr methodID) => + _CallNonvirtualIntMethod(obj, clazz, methodID).integer; + + late final _CallNonvirtualIntMethodA = ptr.ref.CallNonvirtualIntMethodA + .asFunction< + JniResult Function(JObjectPtr obj, JClassPtr clazz, + JMethodIDPtr methodID, ffi.Pointer args)>(); + + int CallNonvirtualIntMethodA(JObjectPtr obj, JClassPtr clazz, + JMethodIDPtr methodID, ffi.Pointer args) => + _CallNonvirtualIntMethodA(obj, clazz, methodID, args).integer; + + late final _CallNonvirtualLongMethod = ptr.ref.CallNonvirtualLongMethod + .asFunction< + JniResult Function( + JObjectPtr obj, JClassPtr clazz, JMethodIDPtr methodID)>(); + + int CallNonvirtualLongMethod( + JObjectPtr obj, JClassPtr clazz, JMethodIDPtr methodID) => + _CallNonvirtualLongMethod(obj, clazz, methodID).long; + + late final _CallNonvirtualLongMethodA = ptr.ref.CallNonvirtualLongMethodA + .asFunction< + JniResult Function(JObjectPtr obj, JClassPtr clazz, + JMethodIDPtr methodID, ffi.Pointer args)>(); + + int CallNonvirtualLongMethodA(JObjectPtr obj, JClassPtr clazz, + JMethodIDPtr methodID, ffi.Pointer args) => + _CallNonvirtualLongMethodA(obj, clazz, methodID, args).long; + + late final _CallNonvirtualFloatMethod = ptr.ref.CallNonvirtualFloatMethod + .asFunction< + JniResult Function( + JObjectPtr obj, JClassPtr clazz, JMethodIDPtr methodID)>(); + + double CallNonvirtualFloatMethod( + JObjectPtr obj, JClassPtr clazz, JMethodIDPtr methodID) => + _CallNonvirtualFloatMethod(obj, clazz, methodID).float; + + late final _CallNonvirtualFloatMethodA = ptr.ref.CallNonvirtualFloatMethodA + .asFunction< + JniResult Function(JObjectPtr obj, JClassPtr clazz, + JMethodIDPtr methodID, ffi.Pointer args)>(); + + double CallNonvirtualFloatMethodA(JObjectPtr obj, JClassPtr clazz, + JMethodIDPtr methodID, ffi.Pointer args) => + _CallNonvirtualFloatMethodA(obj, clazz, methodID, args).float; + + late final _CallNonvirtualDoubleMethod = ptr.ref.CallNonvirtualDoubleMethod + .asFunction< + JniResult Function( + JObjectPtr obj, JClassPtr clazz, JMethodIDPtr methodID)>(); + + double CallNonvirtualDoubleMethod( + JObjectPtr obj, JClassPtr clazz, JMethodIDPtr methodID) => + _CallNonvirtualDoubleMethod(obj, clazz, methodID).doubleFloat; + + late final _CallNonvirtualDoubleMethodA = ptr.ref.CallNonvirtualDoubleMethodA + .asFunction< + JniResult Function(JObjectPtr obj, JClassPtr clazz, + JMethodIDPtr methodID, ffi.Pointer args)>(); + + double CallNonvirtualDoubleMethodA(JObjectPtr obj, JClassPtr clazz, + JMethodIDPtr methodID, ffi.Pointer args) => + _CallNonvirtualDoubleMethodA(obj, clazz, methodID, args).doubleFloat; + + late final _CallNonvirtualVoidMethod = ptr.ref.CallNonvirtualVoidMethod + .asFunction< + JThrowablePtr Function( + JObjectPtr obj, JClassPtr clazz, JMethodIDPtr methodID)>(); + + void CallNonvirtualVoidMethod( + JObjectPtr obj, JClassPtr clazz, JMethodIDPtr methodID) => + _CallNonvirtualVoidMethod(obj, clazz, methodID).check(); + + late final _CallNonvirtualVoidMethodA = ptr.ref.CallNonvirtualVoidMethodA + .asFunction< + JThrowablePtr Function(JObjectPtr obj, JClassPtr clazz, + JMethodIDPtr methodID, ffi.Pointer args)>(); + + void CallNonvirtualVoidMethodA(JObjectPtr obj, JClassPtr clazz, + JMethodIDPtr methodID, ffi.Pointer args) => + _CallNonvirtualVoidMethodA(obj, clazz, methodID, args).check(); + + late final _GetFieldID = ptr.ref.GetFieldID.asFunction< + JniPointerResult Function(JClassPtr clazz, ffi.Pointer name, + ffi.Pointer sig)>(); + + JFieldIDPtr GetFieldID(JClassPtr clazz, ffi.Pointer name, + ffi.Pointer sig) => + _GetFieldID(clazz, name, sig).fieldID; + + late final _GetObjectField = ptr.ref.GetObjectField + .asFunction(); + + JObjectPtr GetObjectField(JObjectPtr obj, JFieldIDPtr fieldID) => + _GetObjectField(obj, fieldID).object; + + late final _GetBooleanField = ptr.ref.GetBooleanField + .asFunction(); + + bool GetBooleanField(JObjectPtr obj, JFieldIDPtr fieldID) => + _GetBooleanField(obj, fieldID).boolean; + + late final _GetByteField = ptr.ref.GetByteField + .asFunction(); + + int GetByteField(JObjectPtr obj, JFieldIDPtr fieldID) => + _GetByteField(obj, fieldID).byte; + + late final _GetCharField = ptr.ref.GetCharField + .asFunction(); + + int GetCharField(JObjectPtr obj, JFieldIDPtr fieldID) => + _GetCharField(obj, fieldID).char; + + late final _GetShortField = ptr.ref.GetShortField + .asFunction(); + + int GetShortField(JObjectPtr obj, JFieldIDPtr fieldID) => + _GetShortField(obj, fieldID).short; + + late final _GetIntField = ptr.ref.GetIntField + .asFunction(); + + int GetIntField(JObjectPtr obj, JFieldIDPtr fieldID) => + _GetIntField(obj, fieldID).integer; + + late final _GetLongField = ptr.ref.GetLongField + .asFunction(); + + int GetLongField(JObjectPtr obj, JFieldIDPtr fieldID) => + _GetLongField(obj, fieldID).long; + + late final _GetFloatField = ptr.ref.GetFloatField + .asFunction(); + + double GetFloatField(JObjectPtr obj, JFieldIDPtr fieldID) => + _GetFloatField(obj, fieldID).float; + + late final _GetDoubleField = ptr.ref.GetDoubleField + .asFunction(); + + double GetDoubleField(JObjectPtr obj, JFieldIDPtr fieldID) => + _GetDoubleField(obj, fieldID).doubleFloat; + + late final _SetObjectField = ptr.ref.SetObjectField.asFunction< + JThrowablePtr Function( + JObjectPtr obj, JFieldIDPtr fieldID, JObjectPtr val)>(); + + void SetObjectField(JObjectPtr obj, JFieldIDPtr fieldID, JObjectPtr val) => + _SetObjectField(obj, fieldID, val).check(); + + late final _SetBooleanField = ptr.ref.SetBooleanField.asFunction< + JThrowablePtr Function(JObjectPtr obj, JFieldIDPtr fieldID, int val)>(); + + void SetBooleanField(JObjectPtr obj, JFieldIDPtr fieldID, int val) => + _SetBooleanField(obj, fieldID, val).check(); + + late final _SetByteField = ptr.ref.SetByteField.asFunction< + JThrowablePtr Function(JObjectPtr obj, JFieldIDPtr fieldID, int val)>(); + + void SetByteField(JObjectPtr obj, JFieldIDPtr fieldID, int val) => + _SetByteField(obj, fieldID, val).check(); + + late final _SetCharField = ptr.ref.SetCharField.asFunction< + JThrowablePtr Function(JObjectPtr obj, JFieldIDPtr fieldID, int val)>(); + + void SetCharField(JObjectPtr obj, JFieldIDPtr fieldID, int val) => + _SetCharField(obj, fieldID, val).check(); + + late final _SetShortField = ptr.ref.SetShortField.asFunction< + JThrowablePtr Function(JObjectPtr obj, JFieldIDPtr fieldID, int val)>(); + + void SetShortField(JObjectPtr obj, JFieldIDPtr fieldID, int val) => + _SetShortField(obj, fieldID, val).check(); + + late final _SetIntField = ptr.ref.SetIntField.asFunction< + JThrowablePtr Function(JObjectPtr obj, JFieldIDPtr fieldID, int val)>(); + + void SetIntField(JObjectPtr obj, JFieldIDPtr fieldID, int val) => + _SetIntField(obj, fieldID, val).check(); + + late final _SetLongField = ptr.ref.SetLongField.asFunction< + JThrowablePtr Function(JObjectPtr obj, JFieldIDPtr fieldID, int val)>(); + + void SetLongField(JObjectPtr obj, JFieldIDPtr fieldID, int val) => + _SetLongField(obj, fieldID, val).check(); + + late final _SetFloatField = ptr.ref.SetFloatField.asFunction< + JThrowablePtr Function( + JObjectPtr obj, JFieldIDPtr fieldID, double val)>(); + + void SetFloatField(JObjectPtr obj, JFieldIDPtr fieldID, double val) => + _SetFloatField(obj, fieldID, val).check(); + + late final _SetDoubleField = ptr.ref.SetDoubleField.asFunction< + JThrowablePtr Function( + JObjectPtr obj, JFieldIDPtr fieldID, double val)>(); + + void SetDoubleField(JObjectPtr obj, JFieldIDPtr fieldID, double val) => + _SetDoubleField(obj, fieldID, val).check(); + + late final _GetStaticMethodID = ptr.ref.GetStaticMethodID.asFunction< + JniPointerResult Function(JClassPtr clazz, ffi.Pointer name, + ffi.Pointer sig)>(); + + JMethodIDPtr GetStaticMethodID(JClassPtr clazz, ffi.Pointer name, + ffi.Pointer sig) => + _GetStaticMethodID(clazz, name, sig).methodID; + + late final _CallStaticObjectMethod = ptr.ref.CallStaticObjectMethod + .asFunction(); + + JObjectPtr CallStaticObjectMethod(JClassPtr clazz, JMethodIDPtr methodID) => + _CallStaticObjectMethod(clazz, methodID).object; + + late final _CallStaticObjectMethodA = ptr.ref.CallStaticObjectMethodA + .asFunction< + JniResult Function(JClassPtr clazz, JMethodIDPtr methodID, + ffi.Pointer args)>(); + + JObjectPtr CallStaticObjectMethodA( + JClassPtr clazz, JMethodIDPtr methodID, ffi.Pointer args) => + _CallStaticObjectMethodA(clazz, methodID, args).object; + + late final _CallStaticBooleanMethod = ptr.ref.CallStaticBooleanMethod + .asFunction(); + + bool CallStaticBooleanMethod(JClassPtr clazz, JMethodIDPtr methodID) => + _CallStaticBooleanMethod(clazz, methodID).boolean; + + late final _CallStaticBooleanMethodA = ptr.ref.CallStaticBooleanMethodA + .asFunction< + JniResult Function(JClassPtr clazz, JMethodIDPtr methodID, + ffi.Pointer args)>(); + + bool CallStaticBooleanMethodA( + JClassPtr clazz, JMethodIDPtr methodID, ffi.Pointer args) => + _CallStaticBooleanMethodA(clazz, methodID, args).boolean; + + late final _CallStaticByteMethod = ptr.ref.CallStaticByteMethod + .asFunction(); + + int CallStaticByteMethod(JClassPtr clazz, JMethodIDPtr methodID) => + _CallStaticByteMethod(clazz, methodID).byte; + + late final _CallStaticByteMethodA = ptr.ref.CallStaticByteMethodA.asFunction< + JniResult Function( + JClassPtr clazz, JMethodIDPtr methodID, ffi.Pointer args)>(); + + int CallStaticByteMethodA( + JClassPtr clazz, JMethodIDPtr methodID, ffi.Pointer args) => + _CallStaticByteMethodA(clazz, methodID, args).byte; + + late final _CallStaticCharMethod = ptr.ref.CallStaticCharMethod + .asFunction(); + + int CallStaticCharMethod(JClassPtr clazz, JMethodIDPtr methodID) => + _CallStaticCharMethod(clazz, methodID).char; + + late final _CallStaticCharMethodA = ptr.ref.CallStaticCharMethodA.asFunction< + JniResult Function( + JClassPtr clazz, JMethodIDPtr methodID, ffi.Pointer args)>(); + + int CallStaticCharMethodA( + JClassPtr clazz, JMethodIDPtr methodID, ffi.Pointer args) => + _CallStaticCharMethodA(clazz, methodID, args).char; + + late final _CallStaticShortMethod = ptr.ref.CallStaticShortMethod + .asFunction(); + + int CallStaticShortMethod(JClassPtr clazz, JMethodIDPtr methodID) => + _CallStaticShortMethod(clazz, methodID).short; + + late final _CallStaticShortMethodA = ptr.ref.CallStaticShortMethodA + .asFunction< + JniResult Function(JClassPtr clazz, JMethodIDPtr methodID, + ffi.Pointer args)>(); + + int CallStaticShortMethodA( + JClassPtr clazz, JMethodIDPtr methodID, ffi.Pointer args) => + _CallStaticShortMethodA(clazz, methodID, args).short; + + late final _CallStaticIntMethod = ptr.ref.CallStaticIntMethod + .asFunction(); + + int CallStaticIntMethod(JClassPtr clazz, JMethodIDPtr methodID) => + _CallStaticIntMethod(clazz, methodID).integer; + + late final _CallStaticIntMethodA = ptr.ref.CallStaticIntMethodA.asFunction< + JniResult Function( + JClassPtr clazz, JMethodIDPtr methodID, ffi.Pointer args)>(); + + int CallStaticIntMethodA( + JClassPtr clazz, JMethodIDPtr methodID, ffi.Pointer args) => + _CallStaticIntMethodA(clazz, methodID, args).integer; + + late final _CallStaticLongMethod = ptr.ref.CallStaticLongMethod + .asFunction(); + + int CallStaticLongMethod(JClassPtr clazz, JMethodIDPtr methodID) => + _CallStaticLongMethod(clazz, methodID).long; + + late final _CallStaticLongMethodA = ptr.ref.CallStaticLongMethodA.asFunction< + JniResult Function( + JClassPtr clazz, JMethodIDPtr methodID, ffi.Pointer args)>(); + + int CallStaticLongMethodA( + JClassPtr clazz, JMethodIDPtr methodID, ffi.Pointer args) => + _CallStaticLongMethodA(clazz, methodID, args).long; + + late final _CallStaticFloatMethod = ptr.ref.CallStaticFloatMethod + .asFunction(); + + double CallStaticFloatMethod(JClassPtr clazz, JMethodIDPtr methodID) => + _CallStaticFloatMethod(clazz, methodID).float; + + late final _CallStaticFloatMethodA = ptr.ref.CallStaticFloatMethodA + .asFunction< + JniResult Function(JClassPtr clazz, JMethodIDPtr methodID, + ffi.Pointer args)>(); + + double CallStaticFloatMethodA( + JClassPtr clazz, JMethodIDPtr methodID, ffi.Pointer args) => + _CallStaticFloatMethodA(clazz, methodID, args).float; + + late final _CallStaticDoubleMethod = ptr.ref.CallStaticDoubleMethod + .asFunction(); + + double CallStaticDoubleMethod(JClassPtr clazz, JMethodIDPtr methodID) => + _CallStaticDoubleMethod(clazz, methodID).doubleFloat; + + late final _CallStaticDoubleMethodA = ptr.ref.CallStaticDoubleMethodA + .asFunction< + JniResult Function(JClassPtr clazz, JMethodIDPtr methodID, + ffi.Pointer args)>(); + + double CallStaticDoubleMethodA( + JClassPtr clazz, JMethodIDPtr methodID, ffi.Pointer args) => + _CallStaticDoubleMethodA(clazz, methodID, args).doubleFloat; + + late final _CallStaticVoidMethod = ptr.ref.CallStaticVoidMethod.asFunction< + JThrowablePtr Function(JClassPtr clazz, JMethodIDPtr methodID)>(); + + void CallStaticVoidMethod(JClassPtr clazz, JMethodIDPtr methodID) => + _CallStaticVoidMethod(clazz, methodID).check(); + + late final _CallStaticVoidMethodA = ptr.ref.CallStaticVoidMethodA.asFunction< + JThrowablePtr Function( + JClassPtr clazz, JMethodIDPtr methodID, ffi.Pointer args)>(); + + void CallStaticVoidMethodA( + JClassPtr clazz, JMethodIDPtr methodID, ffi.Pointer args) => + _CallStaticVoidMethodA(clazz, methodID, args).check(); + + late final _GetStaticFieldID = ptr.ref.GetStaticFieldID.asFunction< + JniPointerResult Function(JClassPtr clazz, ffi.Pointer name, + ffi.Pointer sig)>(); + + JFieldIDPtr GetStaticFieldID(JClassPtr clazz, ffi.Pointer name, + ffi.Pointer sig) => + _GetStaticFieldID(clazz, name, sig).fieldID; + + late final _GetStaticObjectField = ptr.ref.GetStaticObjectField + .asFunction(); + + JObjectPtr GetStaticObjectField(JClassPtr clazz, JFieldIDPtr fieldID) => + _GetStaticObjectField(clazz, fieldID).object; + + late final _GetStaticBooleanField = ptr.ref.GetStaticBooleanField + .asFunction(); + + bool GetStaticBooleanField(JClassPtr clazz, JFieldIDPtr fieldID) => + _GetStaticBooleanField(clazz, fieldID).boolean; + + late final _GetStaticByteField = ptr.ref.GetStaticByteField + .asFunction(); + + int GetStaticByteField(JClassPtr clazz, JFieldIDPtr fieldID) => + _GetStaticByteField(clazz, fieldID).byte; + + late final _GetStaticCharField = ptr.ref.GetStaticCharField + .asFunction(); + + int GetStaticCharField(JClassPtr clazz, JFieldIDPtr fieldID) => + _GetStaticCharField(clazz, fieldID).char; + + late final _GetStaticShortField = ptr.ref.GetStaticShortField + .asFunction(); + + int GetStaticShortField(JClassPtr clazz, JFieldIDPtr fieldID) => + _GetStaticShortField(clazz, fieldID).short; + + late final _GetStaticIntField = ptr.ref.GetStaticIntField + .asFunction(); + + int GetStaticIntField(JClassPtr clazz, JFieldIDPtr fieldID) => + _GetStaticIntField(clazz, fieldID).integer; + + late final _GetStaticLongField = ptr.ref.GetStaticLongField + .asFunction(); + + int GetStaticLongField(JClassPtr clazz, JFieldIDPtr fieldID) => + _GetStaticLongField(clazz, fieldID).long; + + late final _GetStaticFloatField = ptr.ref.GetStaticFloatField + .asFunction(); + + double GetStaticFloatField(JClassPtr clazz, JFieldIDPtr fieldID) => + _GetStaticFloatField(clazz, fieldID).float; + + late final _GetStaticDoubleField = ptr.ref.GetStaticDoubleField + .asFunction(); + + double GetStaticDoubleField(JClassPtr clazz, JFieldIDPtr fieldID) => + _GetStaticDoubleField(clazz, fieldID).doubleFloat; + + late final _SetStaticObjectField = ptr.ref.SetStaticObjectField.asFunction< + JThrowablePtr Function( + JClassPtr clazz, JFieldIDPtr fieldID, JObjectPtr val)>(); + + void SetStaticObjectField( + JClassPtr clazz, JFieldIDPtr fieldID, JObjectPtr val) => + _SetStaticObjectField(clazz, fieldID, val).check(); + + late final _SetStaticBooleanField = ptr.ref.SetStaticBooleanField.asFunction< + JThrowablePtr Function(JClassPtr clazz, JFieldIDPtr fieldID, int val)>(); + + void SetStaticBooleanField(JClassPtr clazz, JFieldIDPtr fieldID, int val) => + _SetStaticBooleanField(clazz, fieldID, val).check(); + + late final _SetStaticByteField = ptr.ref.SetStaticByteField.asFunction< + JThrowablePtr Function(JClassPtr clazz, JFieldIDPtr fieldID, int val)>(); + + void SetStaticByteField(JClassPtr clazz, JFieldIDPtr fieldID, int val) => + _SetStaticByteField(clazz, fieldID, val).check(); + + late final _SetStaticCharField = ptr.ref.SetStaticCharField.asFunction< + JThrowablePtr Function(JClassPtr clazz, JFieldIDPtr fieldID, int val)>(); + + void SetStaticCharField(JClassPtr clazz, JFieldIDPtr fieldID, int val) => + _SetStaticCharField(clazz, fieldID, val).check(); + + late final _SetStaticShortField = ptr.ref.SetStaticShortField.asFunction< + JThrowablePtr Function(JClassPtr clazz, JFieldIDPtr fieldID, int val)>(); + + void SetStaticShortField(JClassPtr clazz, JFieldIDPtr fieldID, int val) => + _SetStaticShortField(clazz, fieldID, val).check(); + + late final _SetStaticIntField = ptr.ref.SetStaticIntField.asFunction< + JThrowablePtr Function(JClassPtr clazz, JFieldIDPtr fieldID, int val)>(); + + void SetStaticIntField(JClassPtr clazz, JFieldIDPtr fieldID, int val) => + _SetStaticIntField(clazz, fieldID, val).check(); + + late final _SetStaticLongField = ptr.ref.SetStaticLongField.asFunction< + JThrowablePtr Function(JClassPtr clazz, JFieldIDPtr fieldID, int val)>(); + + void SetStaticLongField(JClassPtr clazz, JFieldIDPtr fieldID, int val) => + _SetStaticLongField(clazz, fieldID, val).check(); + + late final _SetStaticFloatField = ptr.ref.SetStaticFloatField.asFunction< + JThrowablePtr Function( + JClassPtr clazz, JFieldIDPtr fieldID, double val)>(); + + void SetStaticFloatField(JClassPtr clazz, JFieldIDPtr fieldID, double val) => + _SetStaticFloatField(clazz, fieldID, val).check(); + + late final _SetStaticDoubleField = ptr.ref.SetStaticDoubleField.asFunction< + JThrowablePtr Function( + JClassPtr clazz, JFieldIDPtr fieldID, double val)>(); + + void SetStaticDoubleField(JClassPtr clazz, JFieldIDPtr fieldID, double val) => + _SetStaticDoubleField(clazz, fieldID, val).check(); + + late final _NewString = ptr.ref.NewString.asFunction< + JniResult Function(ffi.Pointer unicodeChars, int len)>(); + + JStringPtr NewString(ffi.Pointer unicodeChars, int len) => + _NewString(unicodeChars, len).object; + + late final _GetStringLength = ptr.ref.GetStringLength + .asFunction(); + + int GetStringLength(JStringPtr string) => _GetStringLength(string).integer; + + late final _GetStringChars = ptr.ref.GetStringChars.asFunction< + JniPointerResult Function( + JStringPtr string, ffi.Pointer isCopy)>(); + + ffi.Pointer GetStringChars( + JStringPtr string, ffi.Pointer isCopy) => + _GetStringChars(string, isCopy).getPointer(); + + late final _ReleaseStringChars = ptr.ref.ReleaseStringChars.asFunction< + JThrowablePtr Function( + JStringPtr string, ffi.Pointer isCopy)>(); + + void ReleaseStringChars(JStringPtr string, ffi.Pointer isCopy) => + _ReleaseStringChars(string, isCopy).check(); + + late final _NewStringUTF = ptr.ref.NewStringUTF + .asFunction bytes)>(); + + JStringPtr NewStringUTF(ffi.Pointer bytes) => + _NewStringUTF(bytes).object; + + late final _GetStringUTFLength = ptr.ref.GetStringUTFLength + .asFunction(); + + int GetStringUTFLength(JStringPtr string) => + _GetStringUTFLength(string).integer; + + late final _GetStringUTFChars = ptr.ref.GetStringUTFChars.asFunction< + JniPointerResult Function( + JStringPtr string, ffi.Pointer isCopy)>(); + + ffi.Pointer GetStringUTFChars( + JStringPtr string, ffi.Pointer isCopy) => + _GetStringUTFChars(string, isCopy).getPointer(); + + late final _ReleaseStringUTFChars = ptr.ref.ReleaseStringUTFChars.asFunction< + JThrowablePtr Function(JStringPtr string, ffi.Pointer utf)>(); + + void ReleaseStringUTFChars(JStringPtr string, ffi.Pointer utf) => + _ReleaseStringUTFChars(string, utf).check(); + + late final _GetArrayLength = + ptr.ref.GetArrayLength.asFunction(); + + int GetArrayLength(JArrayPtr array) => _GetArrayLength(array).integer; + + late final _NewObjectArray = ptr.ref.NewObjectArray.asFunction< + JniResult Function( + int length, JClassPtr elementClass, JObjectPtr initialElement)>(); + + JObjectArrayPtr NewObjectArray( + int length, JClassPtr elementClass, JObjectPtr initialElement) => + _NewObjectArray(length, elementClass, initialElement).object; + + late final _GetObjectArrayElement = ptr.ref.GetObjectArrayElement + .asFunction(); + + JObjectPtr GetObjectArrayElement(JObjectArrayPtr array, int index) => + _GetObjectArrayElement(array, index).object; + + late final _SetObjectArrayElement = ptr.ref.SetObjectArrayElement.asFunction< + JThrowablePtr Function( + JObjectArrayPtr array, int index, JObjectPtr val)>(); + + void SetObjectArrayElement( + JObjectArrayPtr array, int index, JObjectPtr val) => + _SetObjectArrayElement(array, index, val).check(); + + late final _NewBooleanArray = + ptr.ref.NewBooleanArray.asFunction(); + + JBooleanArrayPtr NewBooleanArray(int length) => + _NewBooleanArray(length).object; + + late final _NewByteArray = + ptr.ref.NewByteArray.asFunction(); + + JByteArrayPtr NewByteArray(int length) => _NewByteArray(length).object; + + late final _NewCharArray = + ptr.ref.NewCharArray.asFunction(); + + JCharArrayPtr NewCharArray(int length) => _NewCharArray(length).object; + + late final _NewShortArray = + ptr.ref.NewShortArray.asFunction(); + + JShortArrayPtr NewShortArray(int length) => _NewShortArray(length).object; + + late final _NewIntArray = + ptr.ref.NewIntArray.asFunction(); + + JIntArrayPtr NewIntArray(int length) => _NewIntArray(length).object; + + late final _NewLongArray = + ptr.ref.NewLongArray.asFunction(); + + JLongArrayPtr NewLongArray(int length) => _NewLongArray(length).object; + + late final _NewFloatArray = + ptr.ref.NewFloatArray.asFunction(); + + JFloatArrayPtr NewFloatArray(int length) => _NewFloatArray(length).object; + + late final _NewDoubleArray = + ptr.ref.NewDoubleArray.asFunction(); + + JDoubleArrayPtr NewDoubleArray(int length) => _NewDoubleArray(length).object; + + late final _GetBooleanArrayElements = ptr.ref.GetBooleanArrayElements + .asFunction< + JniPointerResult Function( + JBooleanArrayPtr array, ffi.Pointer isCopy)>(); + + ffi.Pointer GetBooleanArrayElements( + JBooleanArrayPtr array, ffi.Pointer isCopy) => + _GetBooleanArrayElements(array, isCopy).getPointer(); + + late final _GetByteArrayElements = ptr.ref.GetByteArrayElements.asFunction< + JniPointerResult Function( + JByteArrayPtr array, ffi.Pointer isCopy)>(); + + ffi.Pointer GetByteArrayElements( + JByteArrayPtr array, ffi.Pointer isCopy) => + _GetByteArrayElements(array, isCopy).getPointer(); + + late final _GetCharArrayElements = ptr.ref.GetCharArrayElements.asFunction< + JniPointerResult Function( + JCharArrayPtr array, ffi.Pointer isCopy)>(); + + ffi.Pointer GetCharArrayElements( + JCharArrayPtr array, ffi.Pointer isCopy) => + _GetCharArrayElements(array, isCopy).getPointer(); + + late final _GetShortArrayElements = ptr.ref.GetShortArrayElements.asFunction< + JniPointerResult Function( + JShortArrayPtr array, ffi.Pointer isCopy)>(); + + ffi.Pointer GetShortArrayElements( + JShortArrayPtr array, ffi.Pointer isCopy) => + _GetShortArrayElements(array, isCopy).getPointer(); + + late final _GetIntArrayElements = ptr.ref.GetIntArrayElements.asFunction< + JniPointerResult Function( + JIntArrayPtr array, ffi.Pointer isCopy)>(); + + ffi.Pointer GetIntArrayElements( + JIntArrayPtr array, ffi.Pointer isCopy) => + _GetIntArrayElements(array, isCopy).getPointer(); + + late final _GetLongArrayElements = ptr.ref.GetLongArrayElements.asFunction< + JniPointerResult Function( + JLongArrayPtr array, ffi.Pointer isCopy)>(); + + ffi.Pointer GetLongArrayElements( + JLongArrayPtr array, ffi.Pointer isCopy) => + _GetLongArrayElements(array, isCopy).getPointer(); + + late final _GetFloatArrayElements = ptr.ref.GetFloatArrayElements.asFunction< + JniPointerResult Function( + JFloatArrayPtr array, ffi.Pointer isCopy)>(); + + ffi.Pointer GetFloatArrayElements( + JFloatArrayPtr array, ffi.Pointer isCopy) => + _GetFloatArrayElements(array, isCopy).getPointer(); + + late final _GetDoubleArrayElements = ptr.ref.GetDoubleArrayElements + .asFunction< + JniPointerResult Function( + JDoubleArrayPtr array, ffi.Pointer isCopy)>(); + + ffi.Pointer GetDoubleArrayElements( + JDoubleArrayPtr array, ffi.Pointer isCopy) => + _GetDoubleArrayElements(array, isCopy).getPointer(); + + late final _ReleaseBooleanArrayElements = ptr.ref.ReleaseBooleanArrayElements + .asFunction< + JThrowablePtr Function(JBooleanArrayPtr array, + ffi.Pointer elems, int mode)>(); + + void ReleaseBooleanArrayElements(JBooleanArrayPtr array, + ffi.Pointer elems, int mode) => + _ReleaseBooleanArrayElements(array, elems, mode).check(); + + late final _ReleaseByteArrayElements = ptr.ref.ReleaseByteArrayElements + .asFunction< + JThrowablePtr Function( + JByteArrayPtr array, ffi.Pointer elems, int mode)>(); + + void ReleaseByteArrayElements( + JByteArrayPtr array, ffi.Pointer elems, int mode) => + _ReleaseByteArrayElements(array, elems, mode).check(); + + late final _ReleaseCharArrayElements = ptr.ref.ReleaseCharArrayElements + .asFunction< + JThrowablePtr Function( + JCharArrayPtr array, ffi.Pointer elems, int mode)>(); + + void ReleaseCharArrayElements( + JCharArrayPtr array, ffi.Pointer elems, int mode) => + _ReleaseCharArrayElements(array, elems, mode).check(); + + late final _ReleaseShortArrayElements = ptr.ref.ReleaseShortArrayElements + .asFunction< + JThrowablePtr Function(JShortArrayPtr array, + ffi.Pointer elems, int mode)>(); + + void ReleaseShortArrayElements( + JShortArrayPtr array, ffi.Pointer elems, int mode) => + _ReleaseShortArrayElements(array, elems, mode).check(); + + late final _ReleaseIntArrayElements = ptr.ref.ReleaseIntArrayElements + .asFunction< + JThrowablePtr Function( + JIntArrayPtr array, ffi.Pointer elems, int mode)>(); + + void ReleaseIntArrayElements( + JIntArrayPtr array, ffi.Pointer elems, int mode) => + _ReleaseIntArrayElements(array, elems, mode).check(); + + late final _ReleaseLongArrayElements = ptr.ref.ReleaseLongArrayElements + .asFunction< + JThrowablePtr Function( + JLongArrayPtr array, ffi.Pointer elems, int mode)>(); + + void ReleaseLongArrayElements( + JLongArrayPtr array, ffi.Pointer elems, int mode) => + _ReleaseLongArrayElements(array, elems, mode).check(); + + late final _ReleaseFloatArrayElements = ptr.ref.ReleaseFloatArrayElements + .asFunction< + JThrowablePtr Function(JFloatArrayPtr array, + ffi.Pointer elems, int mode)>(); + + void ReleaseFloatArrayElements( + JFloatArrayPtr array, ffi.Pointer elems, int mode) => + _ReleaseFloatArrayElements(array, elems, mode).check(); + + late final _ReleaseDoubleArrayElements = ptr.ref.ReleaseDoubleArrayElements + .asFunction< + JThrowablePtr Function(JDoubleArrayPtr array, + ffi.Pointer elems, int mode)>(); + + void ReleaseDoubleArrayElements( + JDoubleArrayPtr array, ffi.Pointer elems, int mode) => + _ReleaseDoubleArrayElements(array, elems, mode).check(); + + late final _GetBooleanArrayRegion = ptr.ref.GetBooleanArrayRegion.asFunction< + JThrowablePtr Function(JBooleanArrayPtr array, int start, int len, + ffi.Pointer buf)>(); + + void GetBooleanArrayRegion(JBooleanArrayPtr array, int start, int len, + ffi.Pointer buf) => + _GetBooleanArrayRegion(array, start, len, buf).check(); + + late final _GetByteArrayRegion = ptr.ref.GetByteArrayRegion.asFunction< + JThrowablePtr Function(JByteArrayPtr array, int start, int len, + ffi.Pointer buf)>(); + + void GetByteArrayRegion(JByteArrayPtr array, int start, int len, + ffi.Pointer buf) => + _GetByteArrayRegion(array, start, len, buf).check(); + + late final _GetCharArrayRegion = ptr.ref.GetCharArrayRegion.asFunction< + JThrowablePtr Function(JCharArrayPtr array, int start, int len, + ffi.Pointer buf)>(); + + void GetCharArrayRegion(JCharArrayPtr array, int start, int len, + ffi.Pointer buf) => + _GetCharArrayRegion(array, start, len, buf).check(); + + late final _GetShortArrayRegion = ptr.ref.GetShortArrayRegion.asFunction< + JThrowablePtr Function(JShortArrayPtr array, int start, int len, + ffi.Pointer buf)>(); + + void GetShortArrayRegion(JShortArrayPtr array, int start, int len, + ffi.Pointer buf) => + _GetShortArrayRegion(array, start, len, buf).check(); + + late final _GetIntArrayRegion = ptr.ref.GetIntArrayRegion.asFunction< + JThrowablePtr Function(JIntArrayPtr array, int start, int len, + ffi.Pointer buf)>(); + + void GetIntArrayRegion(JIntArrayPtr array, int start, int len, + ffi.Pointer buf) => + _GetIntArrayRegion(array, start, len, buf).check(); + + late final _GetLongArrayRegion = ptr.ref.GetLongArrayRegion.asFunction< + JThrowablePtr Function(JLongArrayPtr array, int start, int len, + ffi.Pointer buf)>(); + + void GetLongArrayRegion(JLongArrayPtr array, int start, int len, + ffi.Pointer buf) => + _GetLongArrayRegion(array, start, len, buf).check(); + + late final _GetFloatArrayRegion = ptr.ref.GetFloatArrayRegion.asFunction< + JThrowablePtr Function(JFloatArrayPtr array, int start, int len, + ffi.Pointer buf)>(); + + void GetFloatArrayRegion(JFloatArrayPtr array, int start, int len, + ffi.Pointer buf) => + _GetFloatArrayRegion(array, start, len, buf).check(); + + late final _GetDoubleArrayRegion = ptr.ref.GetDoubleArrayRegion.asFunction< + JThrowablePtr Function(JDoubleArrayPtr array, int start, int len, + ffi.Pointer buf)>(); + + void GetDoubleArrayRegion(JDoubleArrayPtr array, int start, int len, + ffi.Pointer buf) => + _GetDoubleArrayRegion(array, start, len, buf).check(); + + late final _SetBooleanArrayRegion = ptr.ref.SetBooleanArrayRegion.asFunction< + JThrowablePtr Function(JBooleanArrayPtr array, int start, int len, + ffi.Pointer buf)>(); + + void SetBooleanArrayRegion(JBooleanArrayPtr array, int start, int len, + ffi.Pointer buf) => + _SetBooleanArrayRegion(array, start, len, buf).check(); + + late final _SetByteArrayRegion = ptr.ref.SetByteArrayRegion.asFunction< + JThrowablePtr Function(JByteArrayPtr array, int start, int len, + ffi.Pointer buf)>(); + + void SetByteArrayRegion(JByteArrayPtr array, int start, int len, + ffi.Pointer buf) => + _SetByteArrayRegion(array, start, len, buf).check(); + + late final _SetCharArrayRegion = ptr.ref.SetCharArrayRegion.asFunction< + JThrowablePtr Function(JCharArrayPtr array, int start, int len, + ffi.Pointer buf)>(); + + void SetCharArrayRegion(JCharArrayPtr array, int start, int len, + ffi.Pointer buf) => + _SetCharArrayRegion(array, start, len, buf).check(); + + late final _SetShortArrayRegion = ptr.ref.SetShortArrayRegion.asFunction< + JThrowablePtr Function(JShortArrayPtr array, int start, int len, + ffi.Pointer buf)>(); + + void SetShortArrayRegion(JShortArrayPtr array, int start, int len, + ffi.Pointer buf) => + _SetShortArrayRegion(array, start, len, buf).check(); + + late final _SetIntArrayRegion = ptr.ref.SetIntArrayRegion.asFunction< + JThrowablePtr Function(JIntArrayPtr array, int start, int len, + ffi.Pointer buf)>(); + + void SetIntArrayRegion(JIntArrayPtr array, int start, int len, + ffi.Pointer buf) => + _SetIntArrayRegion(array, start, len, buf).check(); + + late final _SetLongArrayRegion = ptr.ref.SetLongArrayRegion.asFunction< + JThrowablePtr Function(JLongArrayPtr array, int start, int len, + ffi.Pointer buf)>(); + + void SetLongArrayRegion(JLongArrayPtr array, int start, int len, + ffi.Pointer buf) => + _SetLongArrayRegion(array, start, len, buf).check(); + + late final _SetFloatArrayRegion = ptr.ref.SetFloatArrayRegion.asFunction< + JThrowablePtr Function(JFloatArrayPtr array, int start, int len, + ffi.Pointer buf)>(); + + void SetFloatArrayRegion(JFloatArrayPtr array, int start, int len, + ffi.Pointer buf) => + _SetFloatArrayRegion(array, start, len, buf).check(); + + late final _SetDoubleArrayRegion = ptr.ref.SetDoubleArrayRegion.asFunction< + JThrowablePtr Function(JDoubleArrayPtr array, int start, int len, + ffi.Pointer buf)>(); + + void SetDoubleArrayRegion(JDoubleArrayPtr array, int start, int len, + ffi.Pointer buf) => + _SetDoubleArrayRegion(array, start, len, buf).check(); + + late final _RegisterNatives = ptr.ref.RegisterNatives.asFunction< + JniResult Function(JClassPtr clazz, ffi.Pointer methods, + int nMethods)>(); + + int RegisterNatives(JClassPtr clazz, ffi.Pointer methods, + int nMethods) => + _RegisterNatives(clazz, methods, nMethods).integer; + + late final _UnregisterNatives = ptr.ref.UnregisterNatives + .asFunction(); + + int UnregisterNatives(JClassPtr clazz) => _UnregisterNatives(clazz).integer; + + late final _MonitorEnter = + ptr.ref.MonitorEnter.asFunction(); + + int MonitorEnter(JObjectPtr obj) => _MonitorEnter(obj).integer; + + late final _MonitorExit = + ptr.ref.MonitorExit.asFunction(); + + int MonitorExit(JObjectPtr obj) => _MonitorExit(obj).integer; + + late final _GetJavaVM = ptr.ref.GetJavaVM + .asFunction> vm)>(); + + int GetJavaVM(ffi.Pointer> vm) => _GetJavaVM(vm).integer; + + late final _GetStringRegion = ptr.ref.GetStringRegion.asFunction< + JThrowablePtr Function( + JStringPtr str, int start, int len, ffi.Pointer buf)>(); + + void GetStringRegion( + JStringPtr str, int start, int len, ffi.Pointer buf) => + _GetStringRegion(str, start, len, buf).check(); + + late final _GetStringUTFRegion = ptr.ref.GetStringUTFRegion.asFunction< + JThrowablePtr Function( + JStringPtr str, int start, int len, ffi.Pointer buf)>(); + + void GetStringUTFRegion( + JStringPtr str, int start, int len, ffi.Pointer buf) => + _GetStringUTFRegion(str, start, len, buf).check(); + + late final _GetPrimitiveArrayCritical = ptr.ref.GetPrimitiveArrayCritical + .asFunction< + JniPointerResult Function( + JArrayPtr array, ffi.Pointer isCopy)>(); + + ffi.Pointer GetPrimitiveArrayCritical( + JArrayPtr array, ffi.Pointer isCopy) => + _GetPrimitiveArrayCritical(array, isCopy).getPointer(); + + late final _ReleasePrimitiveArrayCritical = + ptr.ref.ReleasePrimitiveArrayCritical.asFunction< + JThrowablePtr Function( + JArrayPtr array, ffi.Pointer carray, int mode)>(); + + void ReleasePrimitiveArrayCritical( + JArrayPtr array, ffi.Pointer carray, int mode) => + _ReleasePrimitiveArrayCritical(array, carray, mode).check(); + + late final _GetStringCritical = ptr.ref.GetStringCritical.asFunction< + JniPointerResult Function( + JStringPtr str, ffi.Pointer isCopy)>(); + + ffi.Pointer GetStringCritical( + JStringPtr str, ffi.Pointer isCopy) => + _GetStringCritical(str, isCopy).getPointer(); + + late final _ReleaseStringCritical = ptr.ref.ReleaseStringCritical.asFunction< + JThrowablePtr Function( + JStringPtr str, ffi.Pointer carray)>(); + + void ReleaseStringCritical(JStringPtr str, ffi.Pointer carray) => + _ReleaseStringCritical(str, carray).check(); + + late final _NewWeakGlobalRef = + ptr.ref.NewWeakGlobalRef.asFunction(); + + JWeakPtr NewWeakGlobalRef(JObjectPtr obj) => _NewWeakGlobalRef(obj).object; + + late final _DeleteWeakGlobalRef = ptr.ref.DeleteWeakGlobalRef + .asFunction(); + + void DeleteWeakGlobalRef(JWeakPtr obj) => _DeleteWeakGlobalRef(obj).check(); + + late final _ExceptionCheck = + ptr.ref.ExceptionCheck.asFunction(); + + bool ExceptionCheck() => _ExceptionCheck().boolean; + + late final _NewDirectByteBuffer = ptr.ref.NewDirectByteBuffer.asFunction< + JniResult Function(ffi.Pointer address, int capacity)>(); + + JObjectPtr NewDirectByteBuffer(ffi.Pointer address, int capacity) => + _NewDirectByteBuffer(address, capacity).object; + + late final _GetDirectBufferAddress = ptr.ref.GetDirectBufferAddress + .asFunction(); + + ffi.Pointer GetDirectBufferAddress(JObjectPtr buf) => + _GetDirectBufferAddress(buf).getPointer(); + + late final _GetDirectBufferCapacity = ptr.ref.GetDirectBufferCapacity + .asFunction(); + + int GetDirectBufferCapacity(JObjectPtr buf) => + _GetDirectBufferCapacity(buf).long; + + late final _GetObjectRefType = + ptr.ref.GetObjectRefType.asFunction(); + + int GetObjectRefType(JObjectPtr obj) => _GetObjectRefType(obj).integer; +} + +/// Wraps over the function pointers in JniAccessorsStruct and exposes them as methods. +class JniAccessors { + final ffi.Pointer ptr; + JniAccessors(this.ptr); + + late final _getClass = ptr.ref.getClass.asFunction< + JniClassLookupResult Function(ffi.Pointer internalName)>(); + JniClassLookupResult getClass(ffi.Pointer internalName) => + _getClass(internalName); + + late final _getFieldID = ptr.ref.getFieldID.asFunction< + JniPointerResult Function(JClassPtr cls, ffi.Pointer fieldName, + ffi.Pointer signature)>(); + JniPointerResult getFieldID(JClassPtr cls, ffi.Pointer fieldName, + ffi.Pointer signature) => + _getFieldID(cls, fieldName, signature); + + late final _getStaticFieldID = ptr.ref.getStaticFieldID.asFunction< + JniPointerResult Function(JClassPtr cls, ffi.Pointer fieldName, + ffi.Pointer signature)>(); + JniPointerResult getStaticFieldID(JClassPtr cls, + ffi.Pointer fieldName, ffi.Pointer signature) => + _getStaticFieldID(cls, fieldName, signature); + + late final _getMethodID = ptr.ref.getMethodID.asFunction< + JniPointerResult Function(JClassPtr cls, ffi.Pointer methodName, + ffi.Pointer signature)>(); + JniPointerResult getMethodID(JClassPtr cls, ffi.Pointer methodName, + ffi.Pointer signature) => + _getMethodID(cls, methodName, signature); + + late final _getStaticMethodID = ptr.ref.getStaticMethodID.asFunction< + JniPointerResult Function(JClassPtr cls, ffi.Pointer methodName, + ffi.Pointer signature)>(); + JniPointerResult getStaticMethodID(JClassPtr cls, + ffi.Pointer methodName, ffi.Pointer signature) => + _getStaticMethodID(cls, methodName, signature); + + late final _newObject = ptr.ref.newObject.asFunction< + JniResult Function( + JClassPtr cls, JMethodIDPtr ctor, ffi.Pointer args)>(); + JniResult newObject( + JClassPtr cls, JMethodIDPtr ctor, ffi.Pointer args) => + _newObject(cls, ctor, args); + + late final _newPrimitiveArray = ptr.ref.newPrimitiveArray + .asFunction(); + JniResult newPrimitiveArray(int length, int type) => + _newPrimitiveArray(length, type); + + late final _newObjectArray = ptr.ref.newObjectArray.asFunction< + JniResult Function( + int length, JClassPtr elementClass, JObjectPtr initialElement)>(); + JniResult newObjectArray( + int length, JClassPtr elementClass, JObjectPtr initialElement) => + _newObjectArray(length, elementClass, initialElement); + + late final _getArrayElement = ptr.ref.getArrayElement + .asFunction(); + JniResult getArrayElement(JArrayPtr array, int index, int type) => + _getArrayElement(array, index, type); + + late final _callMethod = ptr.ref.callMethod.asFunction< + JniResult Function(JObjectPtr obj, JMethodIDPtr methodID, int callType, + ffi.Pointer args)>(); + JniResult callMethod(JObjectPtr obj, JMethodIDPtr methodID, int callType, + ffi.Pointer args) => + _callMethod(obj, methodID, callType, args); + + late final _callStaticMethod = ptr.ref.callStaticMethod.asFunction< + JniResult Function(JClassPtr cls, JMethodIDPtr methodID, int callType, + ffi.Pointer args)>(); + JniResult callStaticMethod(JClassPtr cls, JMethodIDPtr methodID, int callType, + ffi.Pointer args) => + _callStaticMethod(cls, methodID, callType, args); + + late final _getField = ptr.ref.getField.asFunction< + JniResult Function(JObjectPtr obj, JFieldIDPtr fieldID, int callType)>(); + JniResult getField(JObjectPtr obj, JFieldIDPtr fieldID, int callType) => + _getField(obj, fieldID, callType); + + late final _getStaticField = ptr.ref.getStaticField.asFunction< + JniResult Function(JClassPtr cls, JFieldIDPtr fieldID, int callType)>(); + JniResult getStaticField(JClassPtr cls, JFieldIDPtr fieldID, int callType) => + _getStaticField(cls, fieldID, callType); + + late final _getExceptionDetails = ptr.ref.getExceptionDetails + .asFunction(); + JniExceptionDetails getExceptionDetails(JThrowablePtr exception) => + _getExceptionDetails(exception); +} diff --git a/pkgs/jni/lib/src/third_party/jni_bindings_generated.dart b/pkgs/jni/lib/src/third_party/jni_bindings_generated.dart new file mode 100644 index 000000000..892f69e51 --- /dev/null +++ b/pkgs/jni/lib/src/third_party/jni_bindings_generated.dart @@ -0,0 +1,3332 @@ +// Autogenerated file. Do not edit. +// Generated from an annotated version of jni.h provided in Android NDK. +// (NDK Version 23.1.7779620) +// The license for original file is provided below: + +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * JNI specification, as defined by Sun: + * http://java.sun.com/javase/6/docs/technotes/guides/jni/spec/jniTOC.html + * + * Everything here is expected to be VM-neutral. + */ + +// ignore_for_file: always_specify_types +// ignore_for_file: camel_case_types +// ignore_for_file: non_constant_identifier_names +// ignore_for_file: constant_identifier_names +// ignore_for_file: unused_field +// ignore_for_file: unused_element +// coverage:ignore-file + +// AUTO GENERATED FILE, DO NOT EDIT. +// +// Generated by `package:ffigen`. +// ignore_for_file: type=lint +import 'dart:ffi' as ffi; + +/// Bindings for libdartjni.so which is part of jni plugin. +/// +/// It also transitively includes type definitions such as JNIEnv from third_party/jni.h; +/// +/// However, functions prefixed JNI_ are not usable because they are in a different shared library. +/// +/// Regenerate bindings with `flutter pub run ffigen.dart --config ffigen.yaml`. +/// +class JniBindings { + /// Holds the symbol lookup function. + final ffi.Pointer Function(String symbolName) + _lookup; + + /// The symbols are looked up in [dynamicLibrary]. + JniBindings(ffi.DynamicLibrary dynamicLibrary) + : _lookup = dynamicLibrary.lookup; + + /// The symbols are looked up with [lookup]. + JniBindings.fromLookup( + ffi.Pointer Function(String symbolName) + lookup) + : _lookup = lookup; + + ffi.Pointer GetAccessors() { + return _GetAccessors(); + } + + late final _GetAccessorsPtr = + _lookup Function()>>( + 'GetAccessors'); + late final _GetAccessors = + _GetAccessorsPtr.asFunction Function()>(); + + ffi.Pointer GetJavaVM() { + return _GetJavaVM(); + } + + late final _GetJavaVMPtr = + _lookup Function()>>('GetJavaVM'); + late final _GetJavaVM = + _GetJavaVMPtr.asFunction Function()>(); + + ffi.Pointer GetJniEnv() { + return _GetJniEnv(); + } + + late final _GetJniEnvPtr = + _lookup Function()>>('GetJniEnv'); + late final _GetJniEnv = + _GetJniEnvPtr.asFunction Function()>(); + + /// Spawn a JVM with given arguments. + /// + /// Returns JNI_OK on success, and one of the documented JNI error codes on + /// failure. It returns DART_JNI_SINGLETON_EXISTS if an attempt to spawn multiple + /// JVMs is made, even if the underlying API potentially supports multiple VMs. + int SpawnJvm( + ffi.Pointer args, + ) { + return _SpawnJvm( + args, + ); + } + + late final _SpawnJvmPtr = _lookup< + ffi.NativeFunction)>>( + 'SpawnJvm'); + late final _SpawnJvm = + _SpawnJvmPtr.asFunction)>(); + + /// Load class through platform-specific mechanism. + /// + /// Currently uses application classloader on android, + /// and JNIEnv->FindClass on other platforms. + JClassPtr FindClass( + ffi.Pointer name, + ) { + return _FindClass( + name, + ); + } + + late final _FindClassPtr = + _lookup)>>( + 'FindClass'); + late final _FindClass = + _FindClassPtr.asFunction)>(); + + /// Returns Application classLoader (on Android), + /// which can be used to load application and platform classes. + /// + /// On other platforms, NULL is returned. + JObjectPtr GetClassLoader() { + return _GetClassLoader(); + } + + late final _GetClassLoaderPtr = + _lookup>('GetClassLoader'); + late final _GetClassLoader = + _GetClassLoaderPtr.asFunction(); + + /// Returns application context on Android. + /// + /// On other platforms, NULL is returned. + JObjectPtr GetApplicationContext() { + return _GetApplicationContext(); + } + + late final _GetApplicationContextPtr = + _lookup>( + 'GetApplicationContext'); + late final _GetApplicationContext = + _GetApplicationContextPtr.asFunction(); + + /// Returns current activity of the app on Android. + JObjectPtr GetCurrentActivity() { + return _GetCurrentActivity(); + } + + late final _GetCurrentActivityPtr = + _lookup>('GetCurrentActivity'); + late final _GetCurrentActivity = + _GetCurrentActivityPtr.asFunction(); + + int InitDartApiDL( + ffi.Pointer data, + ) { + return _InitDartApiDL( + data, + ); + } + + late final _InitDartApiDLPtr = + _lookup)>>( + 'InitDartApiDL'); + late final _InitDartApiDL = + _InitDartApiDLPtr.asFunction)>(); + + JniResult DartException__ctor( + JStringPtr message, + ) { + return _DartException__ctor( + message, + ); + } + + late final _DartException__ctorPtr = + _lookup>( + 'DartException__ctor'); + late final _DartException__ctor = + _DartException__ctorPtr.asFunction(); + + JniResult PortContinuation__ctor( + int j, + ) { + return _PortContinuation__ctor( + j, + ); + } + + late final _PortContinuation__ctorPtr = + _lookup>( + 'PortContinuation__ctor'); + late final _PortContinuation__ctor = + _PortContinuation__ctorPtr.asFunction(); + + JniResult PortProxy__newInstance( + JObjectPtr binaryName, + int port, + int functionPtr, + ) { + return _PortProxy__newInstance( + binaryName, + port, + functionPtr, + ); + } + + late final _PortProxy__newInstancePtr = _lookup< + ffi.NativeFunction< + JniResult Function( + JObjectPtr, ffi.Int64, ffi.Int64)>>('PortProxy__newInstance'); + late final _PortProxy__newInstance = _PortProxy__newInstancePtr.asFunction< + JniResult Function(JObjectPtr, int, int)>(); + + void resultFor( + ffi.Pointer result, + JObjectPtr object, + ) { + return _resultFor( + result, + object, + ); + } + + late final _resultForPtr = _lookup< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer, JObjectPtr)>>('resultFor'); + late final _resultFor = _resultForPtr + .asFunction, JObjectPtr)>(); + + ffi.Pointer GetGlobalEnv() { + return _GetGlobalEnv(); + } + + late final _GetGlobalEnvPtr = + _lookup Function()>>( + 'GetGlobalEnv'); + late final _GetGlobalEnv = + _GetGlobalEnvPtr.asFunction Function()>(); +} + +/// Types used by JNI API to distinguish between primitive types. +abstract class JniCallType { + static const int booleanType = 0; + static const int byteType = 1; + static const int shortType = 2; + static const int charType = 3; + static const int intType = 4; + static const int longType = 5; + static const int floatType = 6; + static const int doubleType = 7; + static const int objectType = 8; + static const int voidType = 9; +} + +/// Result type for use by JNI. +/// +/// If [exception] is null, it means the result is valid. +/// It's assumed that the caller knows the expected type in [result]. +final class JniResult extends ffi.Struct { + external JValue value; + + external JThrowablePtr exception; +} + +final class JValue extends ffi.Union { + @JBooleanMarker() + external int z; + + @JByteMarker() + external int b; + + @JCharMarker() + external int c; + + @JShortMarker() + external int s; + + @JIntMarker() + external int i; + + @JLongMarker() + external int j; + + @JFloatMarker() + external double f; + + @JDoubleMarker() + external double d; + + external JObjectPtr l; +} + +/// Primitive types that match up with Java equivalents. +typedef JBooleanMarker = ffi.Uint8; +typedef JByteMarker = ffi.Int8; +typedef JCharMarker = ffi.Uint16; +typedef JShortMarker = ffi.Int16; +typedef JIntMarker = ffi.Int32; +typedef JLongMarker = ffi.Int64; +typedef JFloatMarker = ffi.Float; +typedef JDoubleMarker = ffi.Double; + +/// Reference types, in C. +typedef JObjectPtr = ffi.Pointer; +typedef JThrowablePtr = JObjectPtr; + +/// Similar to [JniResult] but for class lookups. +final class JniClassLookupResult extends ffi.Struct { + external JClassPtr value; + + external JThrowablePtr exception; +} + +typedef JClassPtr = JObjectPtr; + +/// Similar to [JniResult] but for method/field ID lookups. +final class JniPointerResult extends ffi.Struct { + external ffi.Pointer value; + + external JThrowablePtr exception; +} + +/// JniExceptionDetails holds 2 jstring objects, one is the result of +/// calling `toString` on exception object, other is stack trace; +final class JniExceptionDetails extends ffi.Struct { + external JStringPtr message; + + external JStringPtr stacktrace; +} + +typedef JStringPtr = JObjectPtr; + +/// This struct contains functions which wrap method call / field access conveniently along with +/// exception checking. +/// +/// Flutter embedding checks for pending JNI exceptions before an FFI transition, which requires us +/// to check for and clear the exception before returning to dart code, which requires these functions +/// to return result types. +final class JniAccessorsStruct extends ffi.Struct { + external ffi.Pointer< + ffi.NativeFunction< + JniClassLookupResult Function( + ffi.Pointer internalName)>> getClass; + + external ffi.Pointer< + ffi.NativeFunction< + JniPointerResult Function( + JClassPtr cls, + ffi.Pointer fieldName, + ffi.Pointer signature)>> getFieldID; + + external ffi.Pointer< + ffi.NativeFunction< + JniPointerResult Function( + JClassPtr cls, + ffi.Pointer fieldName, + ffi.Pointer signature)>> getStaticFieldID; + + external ffi.Pointer< + ffi.NativeFunction< + JniPointerResult Function( + JClassPtr cls, + ffi.Pointer methodName, + ffi.Pointer signature)>> getMethodID; + + external ffi.Pointer< + ffi.NativeFunction< + JniPointerResult Function( + JClassPtr cls, + ffi.Pointer methodName, + ffi.Pointer signature)>> getStaticMethodID; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JClassPtr cls, JMethodIDPtr ctor, ffi.Pointer args)>> + newObject; + + external ffi.Pointer< + ffi + .NativeFunction> + newPrimitiveArray; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JSizeMarker length, JClassPtr elementClass, + JObjectPtr initialElement)>> newObjectArray; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JArrayPtr array, ffi.Int index, ffi.Int type)>> + getArrayElement; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JObjectPtr obj, JMethodIDPtr methodID, + ffi.Int callType, ffi.Pointer args)>> callMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JClassPtr cls, JMethodIDPtr methodID, + ffi.Int callType, ffi.Pointer args)>> callStaticMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JObjectPtr obj, JFieldIDPtr fieldID, ffi.Int callType)>> getField; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JClassPtr cls, JFieldIDPtr fieldID, ffi.Int callType)>> + getStaticField; + + external ffi.Pointer< + ffi.NativeFunction< + JniExceptionDetails Function(JThrowablePtr exception)>> + getExceptionDetails; +} + +typedef JMethodIDPtr = ffi.Pointer; + +final class jmethodID_ extends ffi.Opaque {} + +/// "cardinal indices and sizes" +typedef JSizeMarker = JIntMarker; +typedef JArrayPtr = JObjectPtr; +typedef JFieldIDPtr = ffi.Pointer; + +final class jfieldID_ extends ffi.Opaque {} + +typedef JavaVM = ffi.Pointer; + +/// JNI invocation interface. +final class JNIInvokeInterface extends ffi.Struct { + external ffi.Pointer reserved0; + + external ffi.Pointer reserved1; + + external ffi.Pointer reserved2; + + external ffi + .Pointer vm)>> + DestroyJavaVM; + + external ffi.Pointer< + ffi.NativeFunction< + JIntMarker Function( + ffi.Pointer vm, + ffi.Pointer> p_env, + ffi.Pointer thr_args)>> AttachCurrentThread; + + external ffi + .Pointer vm)>> + DetachCurrentThread; + + external ffi.Pointer< + ffi.NativeFunction< + JIntMarker Function( + ffi.Pointer vm, + ffi.Pointer> p_env, + JIntMarker version)>> GetEnv; + + external ffi.Pointer< + ffi.NativeFunction< + JIntMarker Function( + ffi.Pointer vm, + ffi.Pointer> p_env, + ffi.Pointer thr_args)>> AttachCurrentThreadAsDaemon; +} + +typedef JavaVM1 = ffi.Pointer; +typedef JniEnv = ffi.Pointer; + +/// Table of interface function pointers. +final class JNINativeInterface extends ffi.Struct { + external ffi.Pointer reserved0; + + external ffi.Pointer reserved1; + + external ffi.Pointer reserved2; + + external ffi.Pointer reserved3; + + external ffi.Pointer< + ffi.NativeFunction env)>> + GetVersion; + + external ffi.Pointer< + ffi.NativeFunction< + JClassPtr Function( + ffi.Pointer env, + ffi.Pointer name, + JObjectPtr loader, + ffi.Pointer buf, + JSizeMarker bufLen)>> DefineClass; + + external ffi.Pointer< + ffi.NativeFunction< + JClassPtr Function( + ffi.Pointer env, ffi.Pointer name)>> FindClass; + + external ffi.Pointer< + ffi.NativeFunction< + JMethodIDPtr Function( + ffi.Pointer env, JObjectPtr method)>> + FromReflectedMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JFieldIDPtr Function(ffi.Pointer env, JObjectPtr field)>> + FromReflectedField; + + /// spec doesn't show jboolean parameter + external ffi.Pointer< + ffi.NativeFunction< + JObjectPtr Function( + ffi.Pointer env, + JClassPtr cls, + JMethodIDPtr methodId, + JBooleanMarker isStatic)>> ToReflectedMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JClassPtr Function(ffi.Pointer env, JClassPtr clazz)>> + GetSuperclass; + + external ffi.Pointer< + ffi.NativeFunction< + JBooleanMarker Function(ffi.Pointer env, JClassPtr clazz1, + JClassPtr clazz2)>> IsAssignableFrom; + + /// spec doesn't show jboolean parameter + external ffi.Pointer< + ffi.NativeFunction< + JObjectPtr Function(ffi.Pointer env, JClassPtr cls, + JFieldIDPtr fieldID, JBooleanMarker isStatic)>> ToReflectedField; + + external ffi.Pointer< + ffi.NativeFunction< + JIntMarker Function(ffi.Pointer env, JThrowablePtr obj)>> + Throw; + + external ffi.Pointer< + ffi.NativeFunction< + JIntMarker Function(ffi.Pointer env, JClassPtr clazz, + ffi.Pointer message)>> ThrowNew; + + external ffi.Pointer< + ffi.NativeFunction env)>> + ExceptionOccurred; + + external ffi + .Pointer env)>> + ExceptionDescribe; + + external ffi + .Pointer env)>> + ExceptionClear; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer env, ffi.Pointer msg)>> FatalError; + + external ffi.Pointer< + ffi.NativeFunction< + JIntMarker Function( + ffi.Pointer env, JIntMarker capacity)>> PushLocalFrame; + + external ffi.Pointer< + ffi.NativeFunction< + JObjectPtr Function(ffi.Pointer env, JObjectPtr result)>> + PopLocalFrame; + + external ffi.Pointer< + ffi.NativeFunction< + JObjectPtr Function(ffi.Pointer env, JObjectPtr obj)>> + NewGlobalRef; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer env, JObjectPtr globalRef)>> DeleteGlobalRef; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer env, JObjectPtr localRef)>> + DeleteLocalRef; + + external ffi.Pointer< + ffi.NativeFunction< + JBooleanMarker Function( + ffi.Pointer env, JObjectPtr ref1, JObjectPtr ref2)>> + IsSameObject; + + external ffi.Pointer< + ffi.NativeFunction< + JObjectPtr Function(ffi.Pointer env, JObjectPtr obj)>> + NewLocalRef; + + external ffi.Pointer< + ffi.NativeFunction< + JIntMarker Function( + ffi.Pointer env, JIntMarker capacity)>> + EnsureLocalCapacity; + + external ffi.Pointer< + ffi.NativeFunction< + JObjectPtr Function(ffi.Pointer env, JClassPtr clazz)>> + AllocObject; + + external ffi.Pointer< + ffi.NativeFunction< + JObjectPtr Function(ffi.Pointer env, JClassPtr clazz, + JMethodIDPtr methodID)>> NewObject; + + external ffi.Pointer< + ffi.NativeFunction< + JObjectPtr Function(ffi.Pointer, JClassPtr, JMethodIDPtr, + ffi.Pointer)>> NewObjectV; + + external ffi.Pointer< + ffi.NativeFunction< + JObjectPtr Function(ffi.Pointer env, JClassPtr clazz, + JMethodIDPtr methodID, ffi.Pointer args)>> NewObjectA; + + external ffi.Pointer< + ffi.NativeFunction< + JClassPtr Function(ffi.Pointer env, JObjectPtr obj)>> + GetObjectClass; + + external ffi.Pointer< + ffi.NativeFunction< + JBooleanMarker Function( + ffi.Pointer env, JObjectPtr obj, JClassPtr clazz)>> + IsInstanceOf; + + external ffi.Pointer< + ffi.NativeFunction< + JMethodIDPtr Function( + ffi.Pointer env, + JClassPtr clazz, + ffi.Pointer name, + ffi.Pointer sig)>> GetMethodID; + + external ffi.Pointer< + ffi.NativeFunction< + JObjectPtr Function(ffi.Pointer env, JObjectPtr obj, + JMethodIDPtr methodID)>> CallObjectMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JObjectPtr Function(ffi.Pointer, JObjectPtr, JMethodIDPtr, + ffi.Pointer)>> CallObjectMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JObjectPtr Function( + ffi.Pointer env, + JObjectPtr obj, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallObjectMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JBooleanMarker Function(ffi.Pointer env, JObjectPtr obj, + JMethodIDPtr methodID)>> CallBooleanMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JBooleanMarker Function(ffi.Pointer, JObjectPtr, + JMethodIDPtr, ffi.Pointer)>> CallBooleanMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JBooleanMarker Function( + ffi.Pointer env, + JObjectPtr obj, + JMethodIDPtr methodId, + ffi.Pointer args)>> CallBooleanMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JByteMarker Function(ffi.Pointer env, JObjectPtr obj, + JMethodIDPtr methodID)>> CallByteMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JByteMarker Function(ffi.Pointer, JObjectPtr, JMethodIDPtr, + ffi.Pointer)>> CallByteMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JByteMarker Function( + ffi.Pointer env, + JObjectPtr obj, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallByteMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JCharMarker Function(ffi.Pointer env, JObjectPtr obj, + JMethodIDPtr methodID)>> CallCharMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JCharMarker Function(ffi.Pointer, JObjectPtr, JMethodIDPtr, + ffi.Pointer)>> CallCharMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JCharMarker Function( + ffi.Pointer env, + JObjectPtr obj, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallCharMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JShortMarker Function(ffi.Pointer env, JObjectPtr obj, + JMethodIDPtr methodID)>> CallShortMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JShortMarker Function(ffi.Pointer, JObjectPtr, JMethodIDPtr, + ffi.Pointer)>> CallShortMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JShortMarker Function( + ffi.Pointer env, + JObjectPtr obj, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallShortMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JIntMarker Function(ffi.Pointer env, JObjectPtr obj, + JMethodIDPtr methodID)>> CallIntMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JIntMarker Function(ffi.Pointer, JObjectPtr, JMethodIDPtr, + ffi.Pointer)>> CallIntMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JIntMarker Function(ffi.Pointer env, JObjectPtr obj, + JMethodIDPtr methodID, ffi.Pointer args)>> CallIntMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JLongMarker Function(ffi.Pointer env, JObjectPtr obj, + JMethodIDPtr methodID)>> CallLongMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JLongMarker Function(ffi.Pointer, JObjectPtr, JMethodIDPtr, + ffi.Pointer)>> CallLongMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JLongMarker Function( + ffi.Pointer env, + JObjectPtr obj, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallLongMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JFloatMarker Function(ffi.Pointer env, JObjectPtr obj, + JMethodIDPtr methodID)>> CallFloatMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JFloatMarker Function(ffi.Pointer, JObjectPtr, JMethodIDPtr, + ffi.Pointer)>> CallFloatMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JFloatMarker Function( + ffi.Pointer env, + JObjectPtr obj, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallFloatMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JDoubleMarker Function(ffi.Pointer env, JObjectPtr obj, + JMethodIDPtr methodID)>> CallDoubleMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JDoubleMarker Function(ffi.Pointer, JObjectPtr, JMethodIDPtr, + ffi.Pointer)>> CallDoubleMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JDoubleMarker Function( + ffi.Pointer env, + JObjectPtr obj, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallDoubleMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer env, JObjectPtr obj, + JMethodIDPtr methodID)>> CallVoidMethod; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer, JObjectPtr, JMethodIDPtr, + ffi.Pointer)>> CallVoidMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer env, + JObjectPtr obj, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallVoidMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JObjectPtr Function( + ffi.Pointer env, + JObjectPtr obj, + JClassPtr clazz, + JMethodIDPtr methodID)>> CallNonvirtualObjectMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JObjectPtr Function( + ffi.Pointer, + JObjectPtr, + JClassPtr, + JMethodIDPtr, + ffi.Pointer)>> CallNonvirtualObjectMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JObjectPtr Function( + ffi.Pointer env, + JObjectPtr obj, + JClassPtr clazz, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallNonvirtualObjectMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JBooleanMarker Function( + ffi.Pointer env, + JObjectPtr obj, + JClassPtr clazz, + JMethodIDPtr methodID)>> CallNonvirtualBooleanMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JBooleanMarker Function( + ffi.Pointer, + JObjectPtr, + JClassPtr, + JMethodIDPtr, + ffi.Pointer)>> CallNonvirtualBooleanMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JBooleanMarker Function( + ffi.Pointer env, + JObjectPtr obj, + JClassPtr clazz, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallNonvirtualBooleanMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JByteMarker Function( + ffi.Pointer env, + JObjectPtr obj, + JClassPtr clazz, + JMethodIDPtr methodID)>> CallNonvirtualByteMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JByteMarker Function(ffi.Pointer, JObjectPtr, JClassPtr, + JMethodIDPtr, ffi.Pointer)>> CallNonvirtualByteMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JByteMarker Function( + ffi.Pointer env, + JObjectPtr obj, + JClassPtr clazz, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallNonvirtualByteMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JCharMarker Function( + ffi.Pointer env, + JObjectPtr obj, + JClassPtr clazz, + JMethodIDPtr methodID)>> CallNonvirtualCharMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JCharMarker Function(ffi.Pointer, JObjectPtr, JClassPtr, + JMethodIDPtr, ffi.Pointer)>> CallNonvirtualCharMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JCharMarker Function( + ffi.Pointer env, + JObjectPtr obj, + JClassPtr clazz, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallNonvirtualCharMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JShortMarker Function( + ffi.Pointer env, + JObjectPtr obj, + JClassPtr clazz, + JMethodIDPtr methodID)>> CallNonvirtualShortMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JShortMarker Function(ffi.Pointer, JObjectPtr, JClassPtr, + JMethodIDPtr, ffi.Pointer)>> CallNonvirtualShortMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JShortMarker Function( + ffi.Pointer env, + JObjectPtr obj, + JClassPtr clazz, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallNonvirtualShortMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JIntMarker Function(ffi.Pointer env, JObjectPtr obj, + JClassPtr clazz, JMethodIDPtr methodID)>> CallNonvirtualIntMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JIntMarker Function(ffi.Pointer, JObjectPtr, JClassPtr, + JMethodIDPtr, ffi.Pointer)>> CallNonvirtualIntMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JIntMarker Function( + ffi.Pointer env, + JObjectPtr obj, + JClassPtr clazz, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallNonvirtualIntMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JLongMarker Function( + ffi.Pointer env, + JObjectPtr obj, + JClassPtr clazz, + JMethodIDPtr methodID)>> CallNonvirtualLongMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JLongMarker Function(ffi.Pointer, JObjectPtr, JClassPtr, + JMethodIDPtr, ffi.Pointer)>> CallNonvirtualLongMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JLongMarker Function( + ffi.Pointer env, + JObjectPtr obj, + JClassPtr clazz, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallNonvirtualLongMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JFloatMarker Function( + ffi.Pointer env, + JObjectPtr obj, + JClassPtr clazz, + JMethodIDPtr methodID)>> CallNonvirtualFloatMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JFloatMarker Function(ffi.Pointer, JObjectPtr, JClassPtr, + JMethodIDPtr, ffi.Pointer)>> CallNonvirtualFloatMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JFloatMarker Function( + ffi.Pointer env, + JObjectPtr obj, + JClassPtr clazz, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallNonvirtualFloatMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JDoubleMarker Function( + ffi.Pointer env, + JObjectPtr obj, + JClassPtr clazz, + JMethodIDPtr methodID)>> CallNonvirtualDoubleMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JDoubleMarker Function( + ffi.Pointer, + JObjectPtr, + JClassPtr, + JMethodIDPtr, + ffi.Pointer)>> CallNonvirtualDoubleMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JDoubleMarker Function( + ffi.Pointer env, + JObjectPtr obj, + JClassPtr clazz, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallNonvirtualDoubleMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer env, + JObjectPtr obj, + JClassPtr clazz, + JMethodIDPtr methodID)>> CallNonvirtualVoidMethod; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer, JObjectPtr, JClassPtr, + JMethodIDPtr, ffi.Pointer)>> CallNonvirtualVoidMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer env, + JObjectPtr obj, + JClassPtr clazz, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallNonvirtualVoidMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JFieldIDPtr Function( + ffi.Pointer env, + JClassPtr clazz, + ffi.Pointer name, + ffi.Pointer sig)>> GetFieldID; + + external ffi.Pointer< + ffi.NativeFunction< + JObjectPtr Function(ffi.Pointer env, JObjectPtr obj, + JFieldIDPtr fieldID)>> GetObjectField; + + external ffi.Pointer< + ffi.NativeFunction< + JBooleanMarker Function(ffi.Pointer env, JObjectPtr obj, + JFieldIDPtr fieldID)>> GetBooleanField; + + external ffi.Pointer< + ffi.NativeFunction< + JByteMarker Function(ffi.Pointer env, JObjectPtr obj, + JFieldIDPtr fieldID)>> GetByteField; + + external ffi.Pointer< + ffi.NativeFunction< + JCharMarker Function(ffi.Pointer env, JObjectPtr obj, + JFieldIDPtr fieldID)>> GetCharField; + + external ffi.Pointer< + ffi.NativeFunction< + JShortMarker Function(ffi.Pointer env, JObjectPtr obj, + JFieldIDPtr fieldID)>> GetShortField; + + external ffi.Pointer< + ffi.NativeFunction< + JIntMarker Function(ffi.Pointer env, JObjectPtr obj, + JFieldIDPtr fieldID)>> GetIntField; + + external ffi.Pointer< + ffi.NativeFunction< + JLongMarker Function(ffi.Pointer env, JObjectPtr obj, + JFieldIDPtr fieldID)>> GetLongField; + + external ffi.Pointer< + ffi.NativeFunction< + JFloatMarker Function(ffi.Pointer env, JObjectPtr obj, + JFieldIDPtr fieldID)>> GetFloatField; + + external ffi.Pointer< + ffi.NativeFunction< + JDoubleMarker Function(ffi.Pointer env, JObjectPtr obj, + JFieldIDPtr fieldID)>> GetDoubleField; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer env, JObjectPtr obj, + JFieldIDPtr fieldID, JObjectPtr val)>> SetObjectField; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer env, JObjectPtr obj, + JFieldIDPtr fieldID, JBooleanMarker val)>> SetBooleanField; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer env, JObjectPtr obj, + JFieldIDPtr fieldID, JByteMarker val)>> SetByteField; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer env, JObjectPtr obj, + JFieldIDPtr fieldID, JCharMarker val)>> SetCharField; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer env, JObjectPtr obj, + JFieldIDPtr fieldID, JShortMarker val)>> SetShortField; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer env, JObjectPtr obj, + JFieldIDPtr fieldID, JIntMarker val)>> SetIntField; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer env, JObjectPtr obj, + JFieldIDPtr fieldID, JLongMarker val)>> SetLongField; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer env, JObjectPtr obj, + JFieldIDPtr fieldID, JFloatMarker val)>> SetFloatField; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer env, JObjectPtr obj, + JFieldIDPtr fieldID, JDoubleMarker val)>> SetDoubleField; + + external ffi.Pointer< + ffi.NativeFunction< + JMethodIDPtr Function( + ffi.Pointer env, + JClassPtr clazz, + ffi.Pointer name, + ffi.Pointer sig)>> GetStaticMethodID; + + external ffi.Pointer< + ffi.NativeFunction< + JObjectPtr Function(ffi.Pointer env, JClassPtr clazz, + JMethodIDPtr methodID)>> CallStaticObjectMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JObjectPtr Function(ffi.Pointer, JClassPtr, JMethodIDPtr, + ffi.Pointer)>> CallStaticObjectMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JObjectPtr Function( + ffi.Pointer env, + JClassPtr clazz, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallStaticObjectMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JBooleanMarker Function(ffi.Pointer env, JClassPtr clazz, + JMethodIDPtr methodID)>> CallStaticBooleanMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JBooleanMarker Function(ffi.Pointer, JClassPtr, JMethodIDPtr, + ffi.Pointer)>> CallStaticBooleanMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JBooleanMarker Function( + ffi.Pointer env, + JClassPtr clazz, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallStaticBooleanMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JByteMarker Function(ffi.Pointer env, JClassPtr clazz, + JMethodIDPtr methodID)>> CallStaticByteMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JByteMarker Function(ffi.Pointer, JClassPtr, JMethodIDPtr, + ffi.Pointer)>> CallStaticByteMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JByteMarker Function( + ffi.Pointer env, + JClassPtr clazz, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallStaticByteMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JCharMarker Function(ffi.Pointer env, JClassPtr clazz, + JMethodIDPtr methodID)>> CallStaticCharMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JCharMarker Function(ffi.Pointer, JClassPtr, JMethodIDPtr, + ffi.Pointer)>> CallStaticCharMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JCharMarker Function( + ffi.Pointer env, + JClassPtr clazz, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallStaticCharMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JShortMarker Function(ffi.Pointer env, JClassPtr clazz, + JMethodIDPtr methodID)>> CallStaticShortMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JShortMarker Function(ffi.Pointer, JClassPtr, JMethodIDPtr, + ffi.Pointer)>> CallStaticShortMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JShortMarker Function( + ffi.Pointer env, + JClassPtr clazz, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallStaticShortMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JIntMarker Function(ffi.Pointer env, JClassPtr clazz, + JMethodIDPtr methodID)>> CallStaticIntMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JIntMarker Function(ffi.Pointer, JClassPtr, JMethodIDPtr, + ffi.Pointer)>> CallStaticIntMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JIntMarker Function( + ffi.Pointer env, + JClassPtr clazz, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallStaticIntMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JLongMarker Function(ffi.Pointer env, JClassPtr clazz, + JMethodIDPtr methodID)>> CallStaticLongMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JLongMarker Function(ffi.Pointer, JClassPtr, JMethodIDPtr, + ffi.Pointer)>> CallStaticLongMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JLongMarker Function( + ffi.Pointer env, + JClassPtr clazz, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallStaticLongMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JFloatMarker Function(ffi.Pointer env, JClassPtr clazz, + JMethodIDPtr methodID)>> CallStaticFloatMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JFloatMarker Function(ffi.Pointer, JClassPtr, JMethodIDPtr, + ffi.Pointer)>> CallStaticFloatMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JFloatMarker Function( + ffi.Pointer env, + JClassPtr clazz, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallStaticFloatMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JDoubleMarker Function(ffi.Pointer env, JClassPtr clazz, + JMethodIDPtr methodID)>> CallStaticDoubleMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JDoubleMarker Function(ffi.Pointer, JClassPtr, JMethodIDPtr, + ffi.Pointer)>> CallStaticDoubleMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JDoubleMarker Function( + ffi.Pointer env, + JClassPtr clazz, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallStaticDoubleMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer env, JClassPtr clazz, + JMethodIDPtr methodID)>> CallStaticVoidMethod; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer, JClassPtr, JMethodIDPtr, + ffi.Pointer)>> CallStaticVoidMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer env, + JClassPtr clazz, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallStaticVoidMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JFieldIDPtr Function( + ffi.Pointer env, + JClassPtr clazz, + ffi.Pointer name, + ffi.Pointer sig)>> GetStaticFieldID; + + external ffi.Pointer< + ffi.NativeFunction< + JObjectPtr Function(ffi.Pointer env, JClassPtr clazz, + JFieldIDPtr fieldID)>> GetStaticObjectField; + + external ffi.Pointer< + ffi.NativeFunction< + JBooleanMarker Function(ffi.Pointer env, JClassPtr clazz, + JFieldIDPtr fieldID)>> GetStaticBooleanField; + + external ffi.Pointer< + ffi.NativeFunction< + JByteMarker Function(ffi.Pointer env, JClassPtr clazz, + JFieldIDPtr fieldID)>> GetStaticByteField; + + external ffi.Pointer< + ffi.NativeFunction< + JCharMarker Function(ffi.Pointer env, JClassPtr clazz, + JFieldIDPtr fieldID)>> GetStaticCharField; + + external ffi.Pointer< + ffi.NativeFunction< + JShortMarker Function(ffi.Pointer env, JClassPtr clazz, + JFieldIDPtr fieldID)>> GetStaticShortField; + + external ffi.Pointer< + ffi.NativeFunction< + JIntMarker Function(ffi.Pointer env, JClassPtr clazz, + JFieldIDPtr fieldID)>> GetStaticIntField; + + external ffi.Pointer< + ffi.NativeFunction< + JLongMarker Function(ffi.Pointer env, JClassPtr clazz, + JFieldIDPtr fieldID)>> GetStaticLongField; + + external ffi.Pointer< + ffi.NativeFunction< + JFloatMarker Function(ffi.Pointer env, JClassPtr clazz, + JFieldIDPtr fieldID)>> GetStaticFloatField; + + external ffi.Pointer< + ffi.NativeFunction< + JDoubleMarker Function(ffi.Pointer env, JClassPtr clazz, + JFieldIDPtr fieldID)>> GetStaticDoubleField; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer env, JClassPtr clazz, + JFieldIDPtr fieldID, JObjectPtr val)>> SetStaticObjectField; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer env, JClassPtr clazz, + JFieldIDPtr fieldID, JBooleanMarker val)>> SetStaticBooleanField; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer env, JClassPtr clazz, + JFieldIDPtr fieldID, JByteMarker val)>> SetStaticByteField; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer env, JClassPtr clazz, + JFieldIDPtr fieldID, JCharMarker val)>> SetStaticCharField; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer env, JClassPtr clazz, + JFieldIDPtr fieldID, JShortMarker val)>> SetStaticShortField; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer env, JClassPtr clazz, + JFieldIDPtr fieldID, JIntMarker val)>> SetStaticIntField; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer env, JClassPtr clazz, + JFieldIDPtr fieldID, JLongMarker val)>> SetStaticLongField; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer env, JClassPtr clazz, + JFieldIDPtr fieldID, JFloatMarker val)>> SetStaticFloatField; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer env, JClassPtr clazz, + JFieldIDPtr fieldID, JDoubleMarker val)>> SetStaticDoubleField; + + external ffi.Pointer< + ffi.NativeFunction< + JStringPtr Function( + ffi.Pointer env, + ffi.Pointer unicodeChars, + JSizeMarker len)>> NewString; + + external ffi.Pointer< + ffi.NativeFunction< + JSizeMarker Function( + ffi.Pointer env, JStringPtr string)>> GetStringLength; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Pointer Function( + ffi.Pointer env, + JStringPtr string, + ffi.Pointer isCopy)>> GetStringChars; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer env, JStringPtr string, + ffi.Pointer isCopy)>> ReleaseStringChars; + + external ffi.Pointer< + ffi.NativeFunction< + JStringPtr Function( + ffi.Pointer env, ffi.Pointer bytes)>> + NewStringUTF; + + external ffi.Pointer< + ffi.NativeFunction< + JSizeMarker Function( + ffi.Pointer env, JStringPtr string)>> GetStringUTFLength; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Pointer Function( + ffi.Pointer env, + JStringPtr string, + ffi.Pointer isCopy)>> GetStringUTFChars; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer env, JStringPtr string, + ffi.Pointer utf)>> ReleaseStringUTFChars; + + external ffi.Pointer< + ffi.NativeFunction< + JSizeMarker Function(ffi.Pointer env, JArrayPtr array)>> + GetArrayLength; + + external ffi.Pointer< + ffi.NativeFunction< + JObjectArrayPtr Function( + ffi.Pointer env, + JSizeMarker length, + JClassPtr elementClass, + JObjectPtr initialElement)>> NewObjectArray; + + external ffi.Pointer< + ffi.NativeFunction< + JObjectPtr Function(ffi.Pointer env, JObjectArrayPtr array, + JSizeMarker index)>> GetObjectArrayElement; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer env, JObjectArrayPtr array, + JSizeMarker index, JObjectPtr val)>> SetObjectArrayElement; + + external ffi.Pointer< + ffi.NativeFunction< + JBooleanArrayPtr Function( + ffi.Pointer env, JSizeMarker length)>> NewBooleanArray; + + external ffi.Pointer< + ffi.NativeFunction< + JByteArrayPtr Function( + ffi.Pointer env, JSizeMarker length)>> NewByteArray; + + external ffi.Pointer< + ffi.NativeFunction< + JCharArrayPtr Function( + ffi.Pointer env, JSizeMarker length)>> NewCharArray; + + external ffi.Pointer< + ffi.NativeFunction< + JShortArrayPtr Function( + ffi.Pointer env, JSizeMarker length)>> NewShortArray; + + external ffi.Pointer< + ffi.NativeFunction< + JIntArrayPtr Function( + ffi.Pointer env, JSizeMarker length)>> NewIntArray; + + external ffi.Pointer< + ffi.NativeFunction< + JLongArrayPtr Function( + ffi.Pointer env, JSizeMarker length)>> NewLongArray; + + external ffi.Pointer< + ffi.NativeFunction< + JFloatArrayPtr Function( + ffi.Pointer env, JSizeMarker length)>> NewFloatArray; + + external ffi.Pointer< + ffi.NativeFunction< + JDoubleArrayPtr Function( + ffi.Pointer env, JSizeMarker length)>> NewDoubleArray; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Pointer Function( + ffi.Pointer env, + JBooleanArrayPtr array, + ffi.Pointer isCopy)>> GetBooleanArrayElements; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Pointer Function( + ffi.Pointer env, + JByteArrayPtr array, + ffi.Pointer isCopy)>> GetByteArrayElements; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Pointer Function( + ffi.Pointer env, + JCharArrayPtr array, + ffi.Pointer isCopy)>> GetCharArrayElements; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Pointer Function( + ffi.Pointer env, + JShortArrayPtr array, + ffi.Pointer isCopy)>> GetShortArrayElements; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Pointer Function( + ffi.Pointer env, + JIntArrayPtr array, + ffi.Pointer isCopy)>> GetIntArrayElements; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Pointer Function( + ffi.Pointer env, + JLongArrayPtr array, + ffi.Pointer isCopy)>> GetLongArrayElements; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Pointer Function( + ffi.Pointer env, + JFloatArrayPtr array, + ffi.Pointer isCopy)>> GetFloatArrayElements; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Pointer Function( + ffi.Pointer env, + JDoubleArrayPtr array, + ffi.Pointer isCopy)>> GetDoubleArrayElements; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer env, + JBooleanArrayPtr array, + ffi.Pointer elems, + JIntMarker mode)>> ReleaseBooleanArrayElements; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer env, + JByteArrayPtr array, + ffi.Pointer elems, + JIntMarker mode)>> ReleaseByteArrayElements; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer env, + JCharArrayPtr array, + ffi.Pointer elems, + JIntMarker mode)>> ReleaseCharArrayElements; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer env, + JShortArrayPtr array, + ffi.Pointer elems, + JIntMarker mode)>> ReleaseShortArrayElements; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer env, + JIntArrayPtr array, + ffi.Pointer elems, + JIntMarker mode)>> ReleaseIntArrayElements; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer env, + JLongArrayPtr array, + ffi.Pointer elems, + JIntMarker mode)>> ReleaseLongArrayElements; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer env, + JFloatArrayPtr array, + ffi.Pointer elems, + JIntMarker mode)>> ReleaseFloatArrayElements; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer env, + JDoubleArrayPtr array, + ffi.Pointer elems, + JIntMarker mode)>> ReleaseDoubleArrayElements; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer env, + JBooleanArrayPtr array, + JSizeMarker start, + JSizeMarker len, + ffi.Pointer buf)>> GetBooleanArrayRegion; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer env, + JByteArrayPtr array, + JSizeMarker start, + JSizeMarker len, + ffi.Pointer buf)>> GetByteArrayRegion; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer env, + JCharArrayPtr array, + JSizeMarker start, + JSizeMarker len, + ffi.Pointer buf)>> GetCharArrayRegion; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer env, + JShortArrayPtr array, + JSizeMarker start, + JSizeMarker len, + ffi.Pointer buf)>> GetShortArrayRegion; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer env, + JIntArrayPtr array, + JSizeMarker start, + JSizeMarker len, + ffi.Pointer buf)>> GetIntArrayRegion; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer env, + JLongArrayPtr array, + JSizeMarker start, + JSizeMarker len, + ffi.Pointer buf)>> GetLongArrayRegion; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer env, + JFloatArrayPtr array, + JSizeMarker start, + JSizeMarker len, + ffi.Pointer buf)>> GetFloatArrayRegion; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer env, + JDoubleArrayPtr array, + JSizeMarker start, + JSizeMarker len, + ffi.Pointer buf)>> GetDoubleArrayRegion; + + /// spec shows these without const; some jni.h do, some don't + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer env, + JBooleanArrayPtr array, + JSizeMarker start, + JSizeMarker len, + ffi.Pointer buf)>> SetBooleanArrayRegion; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer env, + JByteArrayPtr array, + JSizeMarker start, + JSizeMarker len, + ffi.Pointer buf)>> SetByteArrayRegion; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer env, + JCharArrayPtr array, + JSizeMarker start, + JSizeMarker len, + ffi.Pointer buf)>> SetCharArrayRegion; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer env, + JShortArrayPtr array, + JSizeMarker start, + JSizeMarker len, + ffi.Pointer buf)>> SetShortArrayRegion; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer env, + JIntArrayPtr array, + JSizeMarker start, + JSizeMarker len, + ffi.Pointer buf)>> SetIntArrayRegion; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer env, + JLongArrayPtr array, + JSizeMarker start, + JSizeMarker len, + ffi.Pointer buf)>> SetLongArrayRegion; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer env, + JFloatArrayPtr array, + JSizeMarker start, + JSizeMarker len, + ffi.Pointer buf)>> SetFloatArrayRegion; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer env, + JDoubleArrayPtr array, + JSizeMarker start, + JSizeMarker len, + ffi.Pointer buf)>> SetDoubleArrayRegion; + + external ffi.Pointer< + ffi.NativeFunction< + JIntMarker Function( + ffi.Pointer env, + JClassPtr clazz, + ffi.Pointer methods, + JIntMarker nMethods)>> RegisterNatives; + + external ffi.Pointer< + ffi.NativeFunction< + JIntMarker Function(ffi.Pointer env, JClassPtr clazz)>> + UnregisterNatives; + + external ffi.Pointer< + ffi.NativeFunction< + JIntMarker Function(ffi.Pointer env, JObjectPtr obj)>> + MonitorEnter; + + external ffi.Pointer< + ffi.NativeFunction< + JIntMarker Function(ffi.Pointer env, JObjectPtr obj)>> + MonitorExit; + + external ffi.Pointer< + ffi.NativeFunction< + JIntMarker Function(ffi.Pointer env, + ffi.Pointer> vm)>> GetJavaVM; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer env, + JStringPtr str, + JSizeMarker start, + JSizeMarker len, + ffi.Pointer buf)>> GetStringRegion; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer env, + JStringPtr str, + JSizeMarker start, + JSizeMarker len, + ffi.Pointer buf)>> GetStringUTFRegion; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Pointer Function( + ffi.Pointer env, + JArrayPtr array, + ffi.Pointer isCopy)>> GetPrimitiveArrayCritical; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer env, + JArrayPtr array, + ffi.Pointer carray, + JIntMarker mode)>> ReleasePrimitiveArrayCritical; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Pointer Function( + ffi.Pointer env, + JStringPtr str, + ffi.Pointer isCopy)>> GetStringCritical; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer env, JStringPtr str, + ffi.Pointer carray)>> ReleaseStringCritical; + + external ffi.Pointer< + ffi.NativeFunction< + JWeakPtr Function(ffi.Pointer env, JObjectPtr obj)>> + NewWeakGlobalRef; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer env, JWeakPtr obj)>> + DeleteWeakGlobalRef; + + external ffi.Pointer< + ffi.NativeFunction env)>> + ExceptionCheck; + + external ffi.Pointer< + ffi.NativeFunction< + JObjectPtr Function( + ffi.Pointer env, + ffi.Pointer address, + JLongMarker capacity)>> NewDirectByteBuffer; + + external ffi.Pointer< + ffi.NativeFunction< + ffi.Pointer Function( + ffi.Pointer env, JObjectPtr buf)>> + GetDirectBufferAddress; + + external ffi.Pointer< + ffi.NativeFunction< + JLongMarker Function(ffi.Pointer env, JObjectPtr buf)>> + GetDirectBufferCapacity; + + /// added in JNI 1.6 + external ffi.Pointer< + ffi.NativeFunction< + ffi.Int32 Function(ffi.Pointer env, JObjectPtr obj)>> + GetObjectRefType; +} + +typedef JniEnv1 = ffi.Pointer; +typedef JObjectArrayPtr = JArrayPtr; +typedef JBooleanArrayPtr = JArrayPtr; +typedef JByteArrayPtr = JArrayPtr; +typedef JCharArrayPtr = JArrayPtr; +typedef JShortArrayPtr = JArrayPtr; +typedef JIntArrayPtr = JArrayPtr; +typedef JLongArrayPtr = JArrayPtr; +typedef JFloatArrayPtr = JArrayPtr; +typedef JDoubleArrayPtr = JArrayPtr; + +final class JNINativeMethod extends ffi.Struct { + external ffi.Pointer name; + + external ffi.Pointer signature; + + external ffi.Pointer fnPtr; +} + +typedef JWeakPtr = JObjectPtr; + +abstract class JObjectRefType { + static const int JNIInvalidRefType = 0; + static const int JNILocalRefType = 1; + static const int JNIGlobalRefType = 2; + static const int JNIWeakGlobalRefType = 3; +} + +final class JavaVMInitArgs extends ffi.Struct { + /// use JNI_VERSION_1_2 or later + @JIntMarker() + external int version; + + @JIntMarker() + external int nOptions; + + external ffi.Pointer options; + + @JBooleanMarker() + external int ignoreUnrecognized; +} + +/// JNI 1.2+ initialization. (As of 1.6, the pre-1.2 structures are no +/// longer supported.) +final class JavaVMOption extends ffi.Struct { + external ffi.Pointer optionString; + + external ffi.Pointer extraInfo; +} + +final class CallbackResult extends ffi.Struct { + external MutexLock lock; + + external ConditionVariable cond; + + @ffi.Int() + external int ready; + + external JObjectPtr object; +} + +typedef MutexLock = pthread_mutex_t; +typedef pthread_mutex_t = __darwin_pthread_mutex_t; +typedef __darwin_pthread_mutex_t = _opaque_pthread_mutex_t; + +final class _opaque_pthread_mutex_t extends ffi.Struct { + @ffi.Long() + external int __sig; + + @ffi.Array.multi([56]) + external ffi.Array __opaque; +} + +typedef ConditionVariable = pthread_cond_t; +typedef pthread_cond_t = __darwin_pthread_cond_t; +typedef __darwin_pthread_cond_t = _opaque_pthread_cond_t; + +final class _opaque_pthread_cond_t extends ffi.Struct { + @ffi.Long() + external int __sig; + + @ffi.Array.multi([40]) + external ffi.Array __opaque; +} + +final class GlobalJniEnvStruct extends ffi.Struct { + external ffi.Pointer reserved0; + + external ffi.Pointer reserved1; + + external ffi.Pointer reserved2; + + external ffi.Pointer reserved3; + + external ffi.Pointer> GetVersion; + + external ffi.Pointer< + ffi.NativeFunction< + JniClassLookupResult Function( + ffi.Pointer name, + JObjectPtr loader, + ffi.Pointer buf, + JSizeMarker bufLen)>> DefineClass; + + external ffi.Pointer< + ffi.NativeFunction< + JniClassLookupResult Function(ffi.Pointer name)>> FindClass; + + external ffi + .Pointer> + FromReflectedMethod; + + external ffi + .Pointer> + FromReflectedField; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JClassPtr cls, JMethodIDPtr methodId, + JBooleanMarker isStatic)>> ToReflectedMethod; + + external ffi.Pointer< + ffi.NativeFunction> + GetSuperclass; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JClassPtr clazz1, JClassPtr clazz2)>> + IsAssignableFrom; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JClassPtr cls, JFieldIDPtr fieldID, JBooleanMarker isStatic)>> + ToReflectedField; + + external ffi + .Pointer> Throw; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JClassPtr clazz, ffi.Pointer message)>> ThrowNew; + + external ffi.Pointer> + ExceptionOccurred; + + external ffi.Pointer> + ExceptionDescribe; + + external ffi.Pointer> + ExceptionClear; + + external ffi.Pointer< + ffi.NativeFunction msg)>> + FatalError; + + external ffi + .Pointer> + PushLocalFrame; + + external ffi + .Pointer> + PopLocalFrame; + + external ffi.Pointer> + NewGlobalRef; + + external ffi + .Pointer> + DeleteGlobalRef; + + external ffi + .Pointer> + DeleteLocalRef; + + external ffi.Pointer< + ffi + .NativeFunction> + IsSameObject; + + external ffi.Pointer> + NewLocalRef; + + external ffi + .Pointer> + EnsureLocalCapacity; + + external ffi.Pointer> + AllocObject; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JClassPtr clazz, JMethodIDPtr methodID)>> + NewObject; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JClassPtr, JMethodIDPtr, ffi.Pointer)>> NewObjectV; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JClassPtr clazz, JMethodIDPtr methodID, + ffi.Pointer args)>> NewObjectA; + + external ffi.Pointer< + ffi.NativeFunction> + GetObjectClass; + + external ffi.Pointer< + ffi + .NativeFunction> + IsInstanceOf; + + external ffi.Pointer< + ffi.NativeFunction< + JniPointerResult Function(JClassPtr clazz, ffi.Pointer name, + ffi.Pointer sig)>> GetMethodID; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JObjectPtr obj, JMethodIDPtr methodID)>> + CallObjectMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JObjectPtr, JMethodIDPtr, ffi.Pointer)>> + CallObjectMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JObjectPtr obj, JMethodIDPtr methodID, + ffi.Pointer args)>> CallObjectMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JObjectPtr obj, JMethodIDPtr methodID)>> + CallBooleanMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JObjectPtr, JMethodIDPtr, ffi.Pointer)>> + CallBooleanMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JObjectPtr obj, JMethodIDPtr methodId, + ffi.Pointer args)>> CallBooleanMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JObjectPtr obj, JMethodIDPtr methodID)>> + CallByteMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JObjectPtr, JMethodIDPtr, ffi.Pointer)>> + CallByteMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JObjectPtr obj, JMethodIDPtr methodID, + ffi.Pointer args)>> CallByteMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JObjectPtr obj, JMethodIDPtr methodID)>> + CallCharMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JObjectPtr, JMethodIDPtr, ffi.Pointer)>> + CallCharMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JObjectPtr obj, JMethodIDPtr methodID, + ffi.Pointer args)>> CallCharMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JObjectPtr obj, JMethodIDPtr methodID)>> + CallShortMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JObjectPtr, JMethodIDPtr, ffi.Pointer)>> + CallShortMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JObjectPtr obj, JMethodIDPtr methodID, + ffi.Pointer args)>> CallShortMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JObjectPtr obj, JMethodIDPtr methodID)>> + CallIntMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JObjectPtr, JMethodIDPtr, ffi.Pointer)>> CallIntMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JObjectPtr obj, JMethodIDPtr methodID, + ffi.Pointer args)>> CallIntMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JObjectPtr obj, JMethodIDPtr methodID)>> + CallLongMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JObjectPtr, JMethodIDPtr, ffi.Pointer)>> + CallLongMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JObjectPtr obj, JMethodIDPtr methodID, + ffi.Pointer args)>> CallLongMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JObjectPtr obj, JMethodIDPtr methodID)>> + CallFloatMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JObjectPtr, JMethodIDPtr, ffi.Pointer)>> + CallFloatMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JObjectPtr obj, JMethodIDPtr methodID, + ffi.Pointer args)>> CallFloatMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JObjectPtr obj, JMethodIDPtr methodID)>> + CallDoubleMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JObjectPtr, JMethodIDPtr, ffi.Pointer)>> + CallDoubleMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JObjectPtr obj, JMethodIDPtr methodID, + ffi.Pointer args)>> CallDoubleMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function(JObjectPtr obj, JMethodIDPtr methodID)>> + CallVoidMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JObjectPtr, JMethodIDPtr, ffi.Pointer)>> + CallVoidMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function(JObjectPtr obj, JMethodIDPtr methodID, + ffi.Pointer args)>> CallVoidMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JObjectPtr obj, JClassPtr clazz, JMethodIDPtr methodID)>> + CallNonvirtualObjectMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JObjectPtr, JClassPtr, JMethodIDPtr, ffi.Pointer)>> + CallNonvirtualObjectMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JObjectPtr obj, + JClassPtr clazz, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallNonvirtualObjectMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JObjectPtr obj, JClassPtr clazz, JMethodIDPtr methodID)>> + CallNonvirtualBooleanMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JObjectPtr, JClassPtr, JMethodIDPtr, ffi.Pointer)>> + CallNonvirtualBooleanMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JObjectPtr obj, + JClassPtr clazz, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallNonvirtualBooleanMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JObjectPtr obj, JClassPtr clazz, JMethodIDPtr methodID)>> + CallNonvirtualByteMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JObjectPtr, JClassPtr, JMethodIDPtr, ffi.Pointer)>> + CallNonvirtualByteMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JObjectPtr obj, + JClassPtr clazz, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallNonvirtualByteMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JObjectPtr obj, JClassPtr clazz, JMethodIDPtr methodID)>> + CallNonvirtualCharMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JObjectPtr, JClassPtr, JMethodIDPtr, ffi.Pointer)>> + CallNonvirtualCharMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JObjectPtr obj, + JClassPtr clazz, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallNonvirtualCharMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JObjectPtr obj, JClassPtr clazz, JMethodIDPtr methodID)>> + CallNonvirtualShortMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JObjectPtr, JClassPtr, JMethodIDPtr, ffi.Pointer)>> + CallNonvirtualShortMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JObjectPtr obj, + JClassPtr clazz, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallNonvirtualShortMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JObjectPtr obj, JClassPtr clazz, JMethodIDPtr methodID)>> + CallNonvirtualIntMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JObjectPtr, JClassPtr, JMethodIDPtr, ffi.Pointer)>> + CallNonvirtualIntMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JObjectPtr obj, + JClassPtr clazz, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallNonvirtualIntMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JObjectPtr obj, JClassPtr clazz, JMethodIDPtr methodID)>> + CallNonvirtualLongMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JObjectPtr, JClassPtr, JMethodIDPtr, ffi.Pointer)>> + CallNonvirtualLongMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JObjectPtr obj, + JClassPtr clazz, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallNonvirtualLongMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JObjectPtr obj, JClassPtr clazz, JMethodIDPtr methodID)>> + CallNonvirtualFloatMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JObjectPtr, JClassPtr, JMethodIDPtr, ffi.Pointer)>> + CallNonvirtualFloatMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JObjectPtr obj, + JClassPtr clazz, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallNonvirtualFloatMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JObjectPtr obj, JClassPtr clazz, JMethodIDPtr methodID)>> + CallNonvirtualDoubleMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JObjectPtr, JClassPtr, JMethodIDPtr, ffi.Pointer)>> + CallNonvirtualDoubleMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JObjectPtr obj, + JClassPtr clazz, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallNonvirtualDoubleMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JObjectPtr obj, JClassPtr clazz, JMethodIDPtr methodID)>> + CallNonvirtualVoidMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JObjectPtr, JClassPtr, JMethodIDPtr, ffi.Pointer)>> + CallNonvirtualVoidMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JObjectPtr obj, + JClassPtr clazz, + JMethodIDPtr methodID, + ffi.Pointer args)>> CallNonvirtualVoidMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JniPointerResult Function(JClassPtr clazz, ffi.Pointer name, + ffi.Pointer sig)>> GetFieldID; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JObjectPtr obj, JFieldIDPtr fieldID)>> + GetObjectField; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JObjectPtr obj, JFieldIDPtr fieldID)>> + GetBooleanField; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JObjectPtr obj, JFieldIDPtr fieldID)>> + GetByteField; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JObjectPtr obj, JFieldIDPtr fieldID)>> + GetCharField; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JObjectPtr obj, JFieldIDPtr fieldID)>> + GetShortField; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JObjectPtr obj, JFieldIDPtr fieldID)>> GetIntField; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JObjectPtr obj, JFieldIDPtr fieldID)>> + GetLongField; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JObjectPtr obj, JFieldIDPtr fieldID)>> + GetFloatField; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JObjectPtr obj, JFieldIDPtr fieldID)>> + GetDoubleField; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JObjectPtr obj, JFieldIDPtr fieldID, JObjectPtr val)>> + SetObjectField; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JObjectPtr obj, JFieldIDPtr fieldID, JBooleanMarker val)>> + SetBooleanField; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JObjectPtr obj, JFieldIDPtr fieldID, JByteMarker val)>> + SetByteField; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JObjectPtr obj, JFieldIDPtr fieldID, JCharMarker val)>> + SetCharField; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JObjectPtr obj, JFieldIDPtr fieldID, JShortMarker val)>> + SetShortField; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JObjectPtr obj, JFieldIDPtr fieldID, JIntMarker val)>> + SetIntField; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JObjectPtr obj, JFieldIDPtr fieldID, JLongMarker val)>> + SetLongField; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JObjectPtr obj, JFieldIDPtr fieldID, JFloatMarker val)>> + SetFloatField; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JObjectPtr obj, JFieldIDPtr fieldID, JDoubleMarker val)>> + SetDoubleField; + + external ffi.Pointer< + ffi.NativeFunction< + JniPointerResult Function(JClassPtr clazz, ffi.Pointer name, + ffi.Pointer sig)>> GetStaticMethodID; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JClassPtr clazz, JMethodIDPtr methodID)>> + CallStaticObjectMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JClassPtr, JMethodIDPtr, ffi.Pointer)>> + CallStaticObjectMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JClassPtr clazz, JMethodIDPtr methodID, + ffi.Pointer args)>> CallStaticObjectMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JClassPtr clazz, JMethodIDPtr methodID)>> + CallStaticBooleanMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JClassPtr, JMethodIDPtr, ffi.Pointer)>> + CallStaticBooleanMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JClassPtr clazz, JMethodIDPtr methodID, + ffi.Pointer args)>> CallStaticBooleanMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JClassPtr clazz, JMethodIDPtr methodID)>> + CallStaticByteMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JClassPtr, JMethodIDPtr, ffi.Pointer)>> + CallStaticByteMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JClassPtr clazz, JMethodIDPtr methodID, + ffi.Pointer args)>> CallStaticByteMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JClassPtr clazz, JMethodIDPtr methodID)>> + CallStaticCharMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JClassPtr, JMethodIDPtr, ffi.Pointer)>> + CallStaticCharMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JClassPtr clazz, JMethodIDPtr methodID, + ffi.Pointer args)>> CallStaticCharMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JClassPtr clazz, JMethodIDPtr methodID)>> + CallStaticShortMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JClassPtr, JMethodIDPtr, ffi.Pointer)>> + CallStaticShortMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JClassPtr clazz, JMethodIDPtr methodID, + ffi.Pointer args)>> CallStaticShortMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JClassPtr clazz, JMethodIDPtr methodID)>> + CallStaticIntMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JClassPtr, JMethodIDPtr, ffi.Pointer)>> + CallStaticIntMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JClassPtr clazz, JMethodIDPtr methodID, + ffi.Pointer args)>> CallStaticIntMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JClassPtr clazz, JMethodIDPtr methodID)>> + CallStaticLongMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JClassPtr, JMethodIDPtr, ffi.Pointer)>> + CallStaticLongMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JClassPtr clazz, JMethodIDPtr methodID, + ffi.Pointer args)>> CallStaticLongMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JClassPtr clazz, JMethodIDPtr methodID)>> + CallStaticFloatMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JClassPtr, JMethodIDPtr, ffi.Pointer)>> + CallStaticFloatMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JClassPtr clazz, JMethodIDPtr methodID, + ffi.Pointer args)>> CallStaticFloatMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JClassPtr clazz, JMethodIDPtr methodID)>> + CallStaticDoubleMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JClassPtr, JMethodIDPtr, ffi.Pointer)>> + CallStaticDoubleMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JClassPtr clazz, JMethodIDPtr methodID, + ffi.Pointer args)>> CallStaticDoubleMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function(JClassPtr clazz, JMethodIDPtr methodID)>> + CallStaticVoidMethod; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JClassPtr, JMethodIDPtr, ffi.Pointer)>> + CallStaticVoidMethodV; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function(JClassPtr clazz, JMethodIDPtr methodID, + ffi.Pointer args)>> CallStaticVoidMethodA; + + external ffi.Pointer< + ffi.NativeFunction< + JniPointerResult Function(JClassPtr clazz, ffi.Pointer name, + ffi.Pointer sig)>> GetStaticFieldID; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JClassPtr clazz, JFieldIDPtr fieldID)>> + GetStaticObjectField; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JClassPtr clazz, JFieldIDPtr fieldID)>> + GetStaticBooleanField; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JClassPtr clazz, JFieldIDPtr fieldID)>> + GetStaticByteField; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JClassPtr clazz, JFieldIDPtr fieldID)>> + GetStaticCharField; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JClassPtr clazz, JFieldIDPtr fieldID)>> + GetStaticShortField; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JClassPtr clazz, JFieldIDPtr fieldID)>> + GetStaticIntField; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JClassPtr clazz, JFieldIDPtr fieldID)>> + GetStaticLongField; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JClassPtr clazz, JFieldIDPtr fieldID)>> + GetStaticFloatField; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JClassPtr clazz, JFieldIDPtr fieldID)>> + GetStaticDoubleField; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JClassPtr clazz, JFieldIDPtr fieldID, JObjectPtr val)>> + SetStaticObjectField; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JClassPtr clazz, JFieldIDPtr fieldID, JBooleanMarker val)>> + SetStaticBooleanField; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JClassPtr clazz, JFieldIDPtr fieldID, JByteMarker val)>> + SetStaticByteField; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JClassPtr clazz, JFieldIDPtr fieldID, JCharMarker val)>> + SetStaticCharField; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JClassPtr clazz, JFieldIDPtr fieldID, JShortMarker val)>> + SetStaticShortField; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JClassPtr clazz, JFieldIDPtr fieldID, JIntMarker val)>> + SetStaticIntField; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JClassPtr clazz, JFieldIDPtr fieldID, JLongMarker val)>> + SetStaticLongField; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JClassPtr clazz, JFieldIDPtr fieldID, JFloatMarker val)>> + SetStaticFloatField; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JClassPtr clazz, JFieldIDPtr fieldID, JDoubleMarker val)>> + SetStaticDoubleField; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + ffi.Pointer unicodeChars, JSizeMarker len)>> + NewString; + + external ffi + .Pointer> + GetStringLength; + + external ffi.Pointer< + ffi.NativeFunction< + JniPointerResult Function( + JStringPtr string, ffi.Pointer isCopy)>> + GetStringChars; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JStringPtr string, ffi.Pointer isCopy)>> + ReleaseStringChars; + + external ffi.Pointer< + ffi.NativeFunction bytes)>> + NewStringUTF; + + external ffi + .Pointer> + GetStringUTFLength; + + external ffi.Pointer< + ffi.NativeFunction< + JniPointerResult Function( + JStringPtr string, ffi.Pointer isCopy)>> + GetStringUTFChars; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JStringPtr string, ffi.Pointer utf)>> + ReleaseStringUTFChars; + + external ffi.Pointer> + GetArrayLength; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JSizeMarker length, JClassPtr elementClass, + JObjectPtr initialElement)>> NewObjectArray; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JObjectArrayPtr array, JSizeMarker index)>> + GetObjectArrayElement; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JObjectArrayPtr array, JSizeMarker index, JObjectPtr val)>> + SetObjectArrayElement; + + external ffi + .Pointer> + NewBooleanArray; + + external ffi + .Pointer> + NewByteArray; + + external ffi + .Pointer> + NewCharArray; + + external ffi + .Pointer> + NewShortArray; + + external ffi + .Pointer> + NewIntArray; + + external ffi + .Pointer> + NewLongArray; + + external ffi + .Pointer> + NewFloatArray; + + external ffi + .Pointer> + NewDoubleArray; + + external ffi.Pointer< + ffi.NativeFunction< + JniPointerResult Function( + JBooleanArrayPtr array, ffi.Pointer isCopy)>> + GetBooleanArrayElements; + + external ffi.Pointer< + ffi.NativeFunction< + JniPointerResult Function( + JByteArrayPtr array, ffi.Pointer isCopy)>> + GetByteArrayElements; + + external ffi.Pointer< + ffi.NativeFunction< + JniPointerResult Function( + JCharArrayPtr array, ffi.Pointer isCopy)>> + GetCharArrayElements; + + external ffi.Pointer< + ffi.NativeFunction< + JniPointerResult Function( + JShortArrayPtr array, ffi.Pointer isCopy)>> + GetShortArrayElements; + + external ffi.Pointer< + ffi.NativeFunction< + JniPointerResult Function( + JIntArrayPtr array, ffi.Pointer isCopy)>> + GetIntArrayElements; + + external ffi.Pointer< + ffi.NativeFunction< + JniPointerResult Function( + JLongArrayPtr array, ffi.Pointer isCopy)>> + GetLongArrayElements; + + external ffi.Pointer< + ffi.NativeFunction< + JniPointerResult Function( + JFloatArrayPtr array, ffi.Pointer isCopy)>> + GetFloatArrayElements; + + external ffi.Pointer< + ffi.NativeFunction< + JniPointerResult Function( + JDoubleArrayPtr array, ffi.Pointer isCopy)>> + GetDoubleArrayElements; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JBooleanArrayPtr array, + ffi.Pointer elems, + JIntMarker mode)>> ReleaseBooleanArrayElements; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JByteArrayPtr array, + ffi.Pointer elems, + JIntMarker mode)>> ReleaseByteArrayElements; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JCharArrayPtr array, + ffi.Pointer elems, + JIntMarker mode)>> ReleaseCharArrayElements; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JShortArrayPtr array, + ffi.Pointer elems, + JIntMarker mode)>> ReleaseShortArrayElements; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JIntArrayPtr array, + ffi.Pointer elems, + JIntMarker mode)>> ReleaseIntArrayElements; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JLongArrayPtr array, + ffi.Pointer elems, + JIntMarker mode)>> ReleaseLongArrayElements; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JFloatArrayPtr array, + ffi.Pointer elems, + JIntMarker mode)>> ReleaseFloatArrayElements; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JDoubleArrayPtr array, + ffi.Pointer elems, + JIntMarker mode)>> ReleaseDoubleArrayElements; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JBooleanArrayPtr array, + JSizeMarker start, + JSizeMarker len, + ffi.Pointer buf)>> GetBooleanArrayRegion; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JByteArrayPtr array, + JSizeMarker start, + JSizeMarker len, + ffi.Pointer buf)>> GetByteArrayRegion; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JCharArrayPtr array, + JSizeMarker start, + JSizeMarker len, + ffi.Pointer buf)>> GetCharArrayRegion; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JShortArrayPtr array, + JSizeMarker start, + JSizeMarker len, + ffi.Pointer buf)>> GetShortArrayRegion; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function(JIntArrayPtr array, JSizeMarker start, + JSizeMarker len, ffi.Pointer buf)>> GetIntArrayRegion; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JLongArrayPtr array, + JSizeMarker start, + JSizeMarker len, + ffi.Pointer buf)>> GetLongArrayRegion; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JFloatArrayPtr array, + JSizeMarker start, + JSizeMarker len, + ffi.Pointer buf)>> GetFloatArrayRegion; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JDoubleArrayPtr array, + JSizeMarker start, + JSizeMarker len, + ffi.Pointer buf)>> GetDoubleArrayRegion; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JBooleanArrayPtr array, + JSizeMarker start, + JSizeMarker len, + ffi.Pointer buf)>> SetBooleanArrayRegion; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JByteArrayPtr array, + JSizeMarker start, + JSizeMarker len, + ffi.Pointer buf)>> SetByteArrayRegion; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JCharArrayPtr array, + JSizeMarker start, + JSizeMarker len, + ffi.Pointer buf)>> SetCharArrayRegion; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JShortArrayPtr array, + JSizeMarker start, + JSizeMarker len, + ffi.Pointer buf)>> SetShortArrayRegion; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function(JIntArrayPtr array, JSizeMarker start, + JSizeMarker len, ffi.Pointer buf)>> SetIntArrayRegion; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JLongArrayPtr array, + JSizeMarker start, + JSizeMarker len, + ffi.Pointer buf)>> SetLongArrayRegion; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JFloatArrayPtr array, + JSizeMarker start, + JSizeMarker len, + ffi.Pointer buf)>> SetFloatArrayRegion; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JDoubleArrayPtr array, + JSizeMarker start, + JSizeMarker len, + ffi.Pointer buf)>> SetDoubleArrayRegion; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + JClassPtr clazz, + ffi.Pointer methods, + JIntMarker nMethods)>> RegisterNatives; + + external ffi.Pointer> + UnregisterNatives; + + external ffi.Pointer> + MonitorEnter; + + external ffi.Pointer> + MonitorExit; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(ffi.Pointer> vm)>> GetJavaVM; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function(JStringPtr str, JSizeMarker start, + JSizeMarker len, ffi.Pointer buf)>> GetStringRegion; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function(JStringPtr str, JSizeMarker start, + JSizeMarker len, ffi.Pointer buf)>> GetStringUTFRegion; + + external ffi.Pointer< + ffi.NativeFunction< + JniPointerResult Function( + JArrayPtr array, ffi.Pointer isCopy)>> + GetPrimitiveArrayCritical; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function(JArrayPtr array, ffi.Pointer carray, + JIntMarker mode)>> ReleasePrimitiveArrayCritical; + + external ffi.Pointer< + ffi.NativeFunction< + JniPointerResult Function( + JStringPtr str, ffi.Pointer isCopy)>> + GetStringCritical; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JStringPtr str, ffi.Pointer carray)>> + ReleaseStringCritical; + + external ffi.Pointer> + NewWeakGlobalRef; + + external ffi.Pointer> + DeleteWeakGlobalRef; + + external ffi.Pointer> ExceptionCheck; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function( + ffi.Pointer address, JLongMarker capacity)>> + NewDirectByteBuffer; + + external ffi + .Pointer> + GetDirectBufferAddress; + + external ffi.Pointer> + GetDirectBufferCapacity; + + external ffi.Pointer> + GetObjectRefType; +} + +/// This file re-exports some JNI constants as enum, because they are not +/// currently being included when they are in macro form. +abstract class JniBooleanValues { + static const int JNI_FALSE = 0; + static const int JNI_TRUE = 1; +} + +abstract class JniVersions { + static const int JNI_VERSION_1_1 = 65537; + static const int JNI_VERSION_1_2 = 65538; + static const int JNI_VERSION_1_4 = 65540; + static const int JNI_VERSION_1_6 = 65542; +} + +abstract class JniErrorCode { + /// no error + static const int JNI_OK = 0; + + /// generic error + static const int JNI_ERR = -1; + + /// thread detached from the VM + static const int JNI_EDETACHED = -2; + + /// JNI version error + static const int JNI_EVERSION = -3; + + /// Out of memory + static const int JNI_ENOMEM = -4; + + /// VM already created + static const int JNI_EEXIST = -5; + + /// Invalid argument + static const int JNI_EINVAL = -6; +} + +abstract class JniBufferWriteBack { + /// copy content, do not free buffer + static const int JNI_COMMIT = 1; + + /// free buffer w/o copying back + static const int JNI_ABORT = 2; +} + +const int DART_JNI_SINGLETON_EXISTS = -99; diff --git a/pkgs/jni/lib/src/types.dart b/pkgs/jni/lib/src/types.dart new file mode 100644 index 000000000..d560b2da6 --- /dev/null +++ b/pkgs/jni/lib/src/types.dart @@ -0,0 +1,54 @@ +// 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. + +import 'dart:ffi'; + +import 'jni.dart'; +import 'jobject.dart'; + +part 'jprimitives.dart'; + +sealed class JType { + const JType(); + + String get signature; +} + +abstract class JObjType extends JType { + /// Number of super types. Distance to the root type. + int get superCount; + + JObjType get superType; + + const JObjType(); + + /// Creates an object from this type using the reference. + T fromRef(Pointer ref); + + JClass getClass() { + if (signature.startsWith('L') && signature.endsWith(';')) { + return Jni.findJClass(signature.substring(1, signature.length - 1)); + } + return Jni.findJClass(signature); + } +} + +/// Lowest common ancestor of two types in the inheritance tree. +JObjType _lowestCommonAncestor(JObjType a, JObjType b) { + while (a.superCount > b.superCount) { + a = a.superType; + } + while (b.superCount > a.superCount) { + b = b.superType; + } + while (a != b) { + a = a.superType; + b = b.superType; + } + return a; +} + +JObjType lowestCommonSuperType(List types) { + return types.reduce(_lowestCommonAncestor); +} diff --git a/pkgs/jni/lib/src/util/jiterator.dart b/pkgs/jni/lib/src/util/jiterator.dart new file mode 100644 index 000000000..0d0122ff1 --- /dev/null +++ b/pkgs/jni/lib/src/util/jiterator.dart @@ -0,0 +1,91 @@ +// Copyright (c) 2023, 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. + +import '../accessors.dart'; +import '../jni.dart'; +import '../jobject.dart'; +import '../third_party/generated_bindings.dart'; +import '../types.dart'; + +final class JIteratorType<$E extends JObject> extends JObjType> { + final JObjType<$E> E; + + const JIteratorType( + this.E, + ); + + @override + String get signature => r"Ljava/util/Iterator;"; + + @override + JIterator<$E> fromRef(JObjectPtr ref) => JIterator.fromRef(E, ref); + + @override + JObjType get superType => const JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => Object.hash(JIteratorType, E); + + @override + bool operator ==(Object other) { + return other.runtimeType == (JIteratorType<$E>) && + other is JIteratorType<$E> && + E == other.E; + } +} + +class JIterator<$E extends JObject> extends JObject implements Iterator<$E> { + @override + // ignore: overridden_fields + late final JObjType $type = type(E); + + final JObjType<$E> E; + + JIterator.fromRef( + this.E, + JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = Jni.findJClass(r"java/util/Iterator"); + + /// The type which includes information such as the signature of this class. + static JIteratorType<$E> type<$E extends JObject>( + JObjType<$E> E, + ) { + return JIteratorType( + E, + ); + } + + $E? _current; + + @override + $E get current => _current as $E; + + static final _hasNextId = + Jni.accessors.getMethodIDOf(_class.reference, r"hasNext", r"()Z"); + bool _hasNext() { + return Jni.accessors.callMethodWithArgs( + reference, _hasNextId, JniCallType.booleanType, []).boolean; + } + + static final _nextId = Jni.accessors + .getMethodIDOf(_class.reference, r"next", r"()Ljava/lang/Object;"); + $E _next() { + return E.fromRef(Jni.accessors.callMethodWithArgs( + reference, _nextId, JniCallType.objectType, []).object); + } + + @override + bool moveNext() { + if (!_hasNext()) { + return false; + } + _current = _next(); + return true; + } +} diff --git a/pkgs/jni/lib/src/util/jlist.dart b/pkgs/jni/lib/src/util/jlist.dart new file mode 100644 index 000000000..9779032a7 --- /dev/null +++ b/pkgs/jni/lib/src/util/jlist.dart @@ -0,0 +1,279 @@ +// Copyright (c) 2023, 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. + +import 'dart:collection'; +import 'dart:ffi'; + +import 'package:jni/src/util/jset.dart'; + +import '../accessors.dart'; +import '../jni.dart'; +import '../jobject.dart'; +import '../jvalues.dart'; +import '../third_party/generated_bindings.dart'; +import '../types.dart'; +import 'jiterator.dart'; + +final class JListType<$E extends JObject> extends JObjType> { + final JObjType<$E> E; + + const JListType( + this.E, + ); + + @override + String get signature => r"Ljava/util/List;"; + + @override + JList<$E> fromRef(JObjectPtr ref) => JList.fromRef(E, ref); + + @override + JObjType get superType => const JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => Object.hash(JListType, E); + + @override + bool operator ==(Object other) { + return other.runtimeType == JListType && other is JListType && E == other.E; + } +} + +class JList<$E extends JObject> extends JObject with ListMixin<$E> { + @override + // ignore: overridden_fields + late final JObjType $type = type(E); + + final JObjType<$E> E; + + JList.fromRef( + this.E, + JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = Jni.findJClass(r"java/util/List"); + + /// The type which includes information such as the signature of this class. + static JListType<$E> type<$E extends JObject>( + JObjType<$E> E, + ) { + return JListType( + E, + ); + } + + static final _arrayListClassRef = Jni.findJClass(r"java/util/ArrayList"); + static final _ctorId = Jni.accessors + .getMethodIDOf(_arrayListClassRef.reference, r"", r"()V"); + JList.array(this.E) + : super.fromRef(Jni.accessors.newObjectWithArgs( + _arrayListClassRef.reference, _ctorId, []).object); + + static final _sizeId = + Jni.accessors.getMethodIDOf(_class.reference, r"size", r"()I"); + @override + int get length => Jni.accessors + .callMethodWithArgs(reference, _sizeId, JniCallType.intType, []).integer; + + @override + set length(int newLength) { + RangeError.checkNotNegative(newLength); + while (length < newLength) { + add(E.fromRef(nullptr)); + } + while (newLength < length) { + removeAt(length - 1); + } + } + + static final _getId = Jni.accessors + .getMethodIDOf(_class.reference, r"get", r"(I)Ljava/lang/Object;"); + @override + $E operator [](int index) { + RangeError.checkValidIndex(index, this); + return E.fromRef(Jni.accessors.callMethodWithArgs( + reference, _getId, JniCallType.objectType, [JValueInt(index)]).object); + } + + static final _setId = Jni.accessors.getMethodIDOf( + _class.reference, r"set", r"(ILjava/lang/Object;)Ljava/lang/Object;"); + @override + void operator []=(int index, $E value) { + RangeError.checkValidIndex(index, this); + E.fromRef(Jni.accessors.callMethodWithArgs(reference, _setId, + JniCallType.objectType, [JValueInt(index), value.reference]).object); + } + + static final _addId = Jni.accessors + .getMethodIDOf(_class.reference, r"add", r"(Ljava/lang/Object;)Z"); + @override + void add($E element) { + Jni.accessors.callMethodWithArgs(reference, _addId, JniCallType.booleanType, + [element.reference]).check(); + } + + static final _collectionClass = Jni.findJClass("java/util/Collection"); + static final _addAllId = Jni.accessors + .getMethodIDOf(_class.reference, r"addAll", r"(Ljava/util/Collection;)Z"); + @override + void addAll(Iterable<$E> iterable) { + if (iterable is JObject && + Jni.env.IsInstanceOf( + (iterable as JObject).reference, _collectionClass.reference)) { + Jni.accessors.callMethodWithArgs(reference, _addAllId, + JniCallType.booleanType, [(iterable as JObject).reference]).boolean; + return; + } + return super.addAll(iterable); + } + + static final _clearId = + Jni.accessors.getMethodIDOf(_class.reference, r"clear", r"()V"); + @override + void clear() { + Jni.accessors.callMethodWithArgs( + reference, _clearId, JniCallType.voidType, []).check(); + } + + static final _containsId = Jni.accessors + .getMethodIDOf(_class.reference, r"contains", r"(Ljava/lang/Object;)Z"); + @override + bool contains(Object? element) { + if (element is! JObject) return false; + return Jni.accessors.callMethodWithArgs(reference, _containsId, + JniCallType.booleanType, [element.reference]).boolean; + } + + static final _getRangeId = Jni.accessors + .getMethodIDOf(_class.reference, r"subList", r"(II)Ljava/util/List;"); + @override + JList<$E> getRange(int start, int end) { + RangeError.checkValidRange(start, end, this.length); + return JListType(E).fromRef( + Jni.accessors.callMethodWithArgs(reference, _getRangeId, + JniCallType.objectType, [JValueInt(start), JValueInt(end)]).object, + ); + } + + static final _indexOfId = Jni.accessors + .getMethodIDOf(_class.reference, r"indexOf", r"(Ljava/lang/Object;)I"); + @override + int indexOf(Object? element, [int start = 0]) { + if (element is! JObject) return -1; + if (start < 0) start = 0; + if (start == 0) { + return Jni.accessors.callMethodWithArgs(reference, _indexOfId, + JniCallType.intType, [element.reference]).integer; + } + return Jni.accessors.callMethodWithArgs( + getRange(start, length).reference, + _indexOfId, + JniCallType.intType, + [element.reference], + ).integer; + } + + static final _insertId = Jni.accessors + .getMethodIDOf(_class.reference, r"add", r"(ILjava/lang/Object;)V"); + @override + void insert(int index, $E element) { + Jni.accessors.callMethodWithArgs(reference, _insertId, JniCallType.voidType, + [JValueInt(index), element.reference]).check(); + } + + static final _insertAllId = Jni.accessors.getMethodIDOf( + _class.reference, r"addAll", r"(ILjava/util/Collection;)Z"); + @override + void insertAll(int index, Iterable<$E> iterable) { + if (iterable is JObject && + Jni.env.IsInstanceOf( + (iterable as JObject).reference, _collectionClass.reference)) { + Jni.accessors.callMethodWithArgs( + reference, + _insertAllId, + JniCallType.booleanType, + [JValueInt(index), (iterable as JObject).reference], + ).boolean; + return; + } + super.insertAll(index, iterable); + } + + static final _isEmptyId = + Jni.accessors.getMethodIDOf(_class.reference, r"isEmpty", r"()Z"); + @override + bool get isEmpty => Jni.accessors.callMethodWithArgs( + reference, _isEmptyId, JniCallType.booleanType, []).boolean; + + @override + bool get isNotEmpty => !isEmpty; + + static final _iteratorId = Jni.accessors + .getMethodIDOf(_class.reference, r"iterator", r"()Ljava/util/Iterator;"); + @override + JIterator<$E> get iterator => + JIteratorType(E).fromRef(Jni.accessors.callMethodWithArgs( + reference, _iteratorId, JniCallType.objectType, []).object); + + static final _lastIndexOfId = Jni.accessors.getMethodIDOf( + _class.reference, r"lastIndexOf", r"(Ljava/lang/Object;)I"); + @override + int lastIndexOf(Object? element, [int? start]) { + if (element is! JObject) return -1; + if (start == null || start >= this.length) start = this.length - 1; + if (start == this.length - 1) { + return Jni.accessors.callMethodWithArgs(reference, _lastIndexOfId, + JniCallType.intType, [element.reference]).integer; + } + final range = getRange(start, length); + final res = Jni.accessors.callMethodWithArgs( + range.reference, + _lastIndexOfId, + JniCallType.intType, + [element.reference], + ).integer; + range.release(); + return res; + } + + static final _removeId = Jni.accessors + .getMethodIDOf(_class.reference, r"remove", r"(Ljava/lang/Object;)Z"); + @override + bool remove(Object? element) { + if (element is! JObject) return false; + return Jni.accessors.callMethodWithArgs(reference, _removeId, + JniCallType.booleanType, [element.reference]).boolean; + } + + static final _removeAtId = Jni.accessors + .getMethodIDOf(_class.reference, r"remove", r"(I)Ljava/lang/Object;"); + @override + $E removeAt(int index) { + return E.fromRef(Jni.accessors.callMethodWithArgs(reference, _removeAtId, + JniCallType.objectType, [JValueInt(index)]).object); + } + + @override + void removeRange(int start, int end) { + final range = getRange(start, end); + range.clear(); + range.release(); + } + + @override + JSet<$E> toSet() { + return toJSet(E); + } +} + +extension ToJavaList on Iterable { + JList toJList(JObjType type) { + final list = JList.array(type); + list.addAll(this); + return list; + } +} diff --git a/pkgs/jni/lib/src/util/jmap.dart b/pkgs/jni/lib/src/util/jmap.dart new file mode 100644 index 000000000..73a6d6237 --- /dev/null +++ b/pkgs/jni/lib/src/util/jmap.dart @@ -0,0 +1,185 @@ +// Copyright (c) 2023, 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. + +import 'dart:collection'; + +import '../accessors.dart'; +import '../jni.dart'; +import '../jobject.dart'; +import '../third_party/jni_bindings_generated.dart'; +import '../types.dart'; +import 'jset.dart'; + +final class JMapType<$K extends JObject, $V extends JObject> + extends JObjType> { + final JObjType<$K> K; + final JObjType<$V> V; + + const JMapType( + this.K, + this.V, + ); + + @override + String get signature => r"Ljava/util/Map;"; + + @override + JMap<$K, $V> fromRef(JObjectPtr ref) => JMap.fromRef(K, V, ref); + + @override + JObjType get superType => const JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => Object.hash(JMapType, K, V); + + @override + bool operator ==(Object other) { + return other.runtimeType == (JMapType<$K, $V>) && + other is JMapType<$K, $V> && + K == other.K && + V == other.V; + } +} + +class JMap<$K extends JObject, $V extends JObject> extends JObject + with MapMixin<$K, $V> { + @override + // ignore: overridden_fields + late final JObjType $type = type(K, V); + + final JObjType<$K> K; + final JObjType<$V> V; + + JMap.fromRef( + this.K, + this.V, + JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = Jni.findJClass(r"java/util/Map"); + + /// The type which includes information such as the signature of this class. + static JMapType<$K, $V> type<$K extends JObject, $V extends JObject>( + JObjType<$K> K, + JObjType<$V> V, + ) { + return JMapType( + K, + V, + ); + } + + static final _hashMapClass = Jni.findJClass(r"java/util/HashMap"); + static final _ctorId = + Jni.accessors.getMethodIDOf(_hashMapClass.reference, r"", r"()V"); + JMap.hash(this.K, this.V) + : super.fromRef(Jni.accessors + .newObjectWithArgs(_hashMapClass.reference, _ctorId, []).object); + + static final _getId = Jni.accessors.getMethodIDOf( + _class.reference, r"get", r"(Ljava/lang/Object;)Ljava/lang/Object;"); + @override + $V? operator [](Object? key) { + if (key is! JObject) { + return null; + } + final value = V.fromRef(Jni.accessors.callMethodWithArgs( + reference, _getId, JniCallType.objectType, [key.reference]).object); + return value.isNull ? null : value; + } + + static final _putId = Jni.accessors.getMethodIDOf(_class.reference, r"put", + r"(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); + @override + void operator []=($K key, $V value) { + Jni.accessors.callMethodWithArgs(reference, _putId, JniCallType.objectType, + [key.reference, value.reference]).object; + } + + static final _addAllId = Jni.accessors + .getMethodIDOf(_class.reference, r"putAll", r"(Ljava/util/Map;)V"); + @override + void addAll(Map<$K, $V> other) { + if (other is JMap<$K, $V>) { + Jni.accessors.callMethodWithArgs(reference, _addAllId, + JniCallType.voidType, [other.reference]).check(); + return; + } + super.addAll(other); + } + + static final _clearId = + Jni.accessors.getMethodIDOf(_class.reference, r"clear", r"()V"); + @override + void clear() { + Jni.accessors.callMethodWithArgs( + reference, _clearId, JniCallType.voidType, []).check(); + } + + static final _containsKeyId = Jni.accessors.getMethodIDOf( + _class.reference, r"containsKey", r"(Ljava/lang/Object;)Z"); + @override + bool containsKey(Object? key) { + if (key is! JObject) { + return false; + } + return Jni.accessors.callMethodWithArgs(reference, _containsKeyId, + JniCallType.booleanType, [key.reference]).boolean; + } + + static final _containsValueId = Jni.accessors.getMethodIDOf( + _class.reference, r"containsValue", r"(Ljava/lang/Object;)Z"); + @override + bool containsValue(Object? value) { + if (value is! JObject) { + return false; + } + return Jni.accessors.callMethodWithArgs(reference, _containsValueId, + JniCallType.booleanType, [value.reference]).boolean; + } + + static final isEmptyId = + Jni.accessors.getMethodIDOf(_class.reference, r"isEmpty", r"()Z"); + @override + bool get isEmpty => Jni.accessors.callMethodWithArgs( + reference, isEmptyId, JniCallType.booleanType, []).boolean; + + @override + bool get isNotEmpty => !isEmpty; + + static final _keysId = Jni.accessors + .getMethodIDOf(_class.reference, r"keySet", r"()Ljava/util/Set;"); + @override + JSet<$K> get keys => JSetType(K).fromRef(Jni.accessors.callMethodWithArgs( + reference, _keysId, JniCallType.objectType, []).object); + + static final _sizeId = + Jni.accessors.getMethodIDOf(_class.reference, r"size", r"()I"); + @override + int get length => Jni.accessors + .callMethodWithArgs(reference, _sizeId, JniCallType.intType, []).integer; + + static final _removeId = Jni.accessors.getMethodIDOf( + _class.reference, r"remove", r"(Ljava/lang/Object;)Ljava/lang/Object;"); + @override + $V? remove(Object? key) { + if (key is! JObject) { + return null; + } + final value = V.fromRef(Jni.accessors.callMethodWithArgs( + reference, _removeId, JniCallType.objectType, [key.reference]).object); + return value.isNull ? null : value; + } +} + +extension ToJavaMap on Map { + JMap toJMap(JObjType keyType, JObjType valueType) { + final map = JMap.hash(keyType, valueType); + map.addAll(this); + return map; + } +} diff --git a/pkgs/jni/lib/src/util/jset.dart b/pkgs/jni/lib/src/util/jset.dart new file mode 100644 index 000000000..df5100361 --- /dev/null +++ b/pkgs/jni/lib/src/util/jset.dart @@ -0,0 +1,214 @@ +// Copyright (c) 2023, 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. + +import 'dart:collection'; + +import 'package:jni/src/third_party/generated_bindings.dart'; + +import '../accessors.dart'; +import '../jni.dart'; +import '../jobject.dart'; +import '../types.dart'; +import 'jiterator.dart'; + +final class JSetType<$E extends JObject> extends JObjType> { + final JObjType<$E> E; + + const JSetType( + this.E, + ); + + @override + String get signature => r"Ljava/util/Set;"; + + @override + JSet<$E> fromRef(JObjectPtr ref) => JSet.fromRef(E, ref); + + @override + JObjType get superType => const JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => Object.hash(JSetType, E); + + @override + bool operator ==(Object other) { + return other.runtimeType == (JSetType<$E>) && + other is JSetType<$E> && + E == other.E; + } +} + +class JSet<$E extends JObject> extends JObject with SetMixin<$E> { + @override + // ignore: overridden_fields + late final JObjType $type = type(E); + + final JObjType<$E> E; + + JSet.fromRef( + this.E, + JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = Jni.findJClass(r"java/util/Set"); + + /// The type which includes information such as the signature of this class. + static JSetType<$E> type<$E extends JObject>( + JObjType<$E> E, + ) { + return JSetType( + E, + ); + } + + static final _hashSetClass = Jni.findJClass(r"java/util/HashSet"); + static final _ctorId = + Jni.accessors.getMethodIDOf(_hashSetClass.reference, r"", r"()V"); + JSet.hash(this.E) + : super.fromRef(Jni.accessors + .newObjectWithArgs(_hashSetClass.reference, _ctorId, []).object); + + static final _addId = Jni.accessors + .getMethodIDOf(_class.reference, r"add", r"(Ljava/lang/Object;)Z"); + @override + bool add($E value) { + return Jni.accessors.callMethodWithArgs( + reference, _addId, JniCallType.booleanType, [value.reference]).boolean; + } + + static final _addAllId = Jni.accessors + .getMethodIDOf(_class.reference, r"addAll", r"(Ljava/util/Collection;)Z"); + @override + void addAll(Iterable<$E> elements) { + if (elements is JObject && + Jni.env.IsInstanceOf( + (elements as JObject).reference, _collectionClass.reference)) { + Jni.accessors.callMethodWithArgs( + reference, + _addAllId, + JniCallType.booleanType, + [(elements as JObject).reference], + ).boolean; + return; + } + return super.addAll(elements); + } + + static final _clearId = + Jni.accessors.getMethodIDOf(_class.reference, r"clear", r"()V"); + @override + void clear() { + return Jni.accessors.callMethodWithArgs( + reference, _clearId, JniCallType.voidType, []).check(); + } + + static final _containsId = Jni.accessors + .getMethodIDOf(_class.reference, r"contains", r"(Ljava/lang/Object;)Z"); + + @override + bool contains(Object? element) { + if (element is! JObject) { + return false; + } + return Jni.accessors.callMethodWithArgs(reference, _containsId, + JniCallType.booleanType, [element.reference]).boolean; + } + + static final _containsAllId = Jni.accessors.getMethodIDOf( + _class.reference, r"containsAll", r"(Ljava/util/Collection;)Z"); + static final _collectionClass = Jni.findJClass("java/util/Collection"); + @override + bool containsAll(Iterable other) { + if (other is JObject && + Jni.env.IsInstanceOf( + (other as JObject).reference, _collectionClass.reference)) { + return Jni.accessors.callMethodWithArgs(reference, _containsAllId, + JniCallType.booleanType, [(other as JObject).reference]).boolean; + } + return super.containsAll(other); + } + + static final _isEmptyId = + Jni.accessors.getMethodIDOf(_class.reference, r"isEmpty", r"()Z"); + @override + bool get isEmpty => Jni.accessors.callMethodWithArgs( + reference, _isEmptyId, JniCallType.booleanType, []).boolean; + + @override + bool get isNotEmpty => !isEmpty; + + static final _iteratorId = Jni.accessors + .getMethodIDOf(_class.reference, r"iterator", r"()Ljava/util/Iterator;"); + @override + JIterator<$E> get iterator => + JIteratorType(E).fromRef(Jni.accessors.callMethodWithArgs( + reference, _iteratorId, JniCallType.objectType, []).object); + + static final _sizeId = + Jni.accessors.getMethodIDOf(_class.reference, r"size", r"()I"); + @override + int get length => Jni.accessors + .callMethodWithArgs(reference, _sizeId, JniCallType.intType, []).integer; + + static final _removeId = Jni.accessors + .getMethodIDOf(_class.reference, r"remove", r"(Ljava/lang/Object;)Z"); + @override + bool remove(Object? value) { + if (value is! $E) { + return false; + } + return Jni.accessors.callMethodWithArgs(reference, _removeId, + JniCallType.booleanType, [value.reference]).boolean; + } + + static final _removeAllId = Jni.accessors.getMethodIDOf( + _class.reference, r"removeAll", r"(Ljava/util/Collection;)Z"); + @override + void removeAll(Iterable elements) { + if (elements is JObject && + Jni.env.IsInstanceOf( + (elements as JObject).reference, _collectionClass.reference)) { + Jni.accessors.callMethodWithArgs(reference, _removeAllId, + JniCallType.booleanType, [(elements as JObject).reference]).boolean; + return; + } + return super.removeAll(elements); + } + + static final _retainAllId = Jni.accessors.getMethodIDOf( + _class.reference, r"retainAll", r"(Ljava/util/Collection;)Z"); + @override + void retainAll(Iterable elements) { + if (elements is JObject && + Jni.env.IsInstanceOf( + (elements as JObject).reference, _collectionClass.reference)) { + Jni.accessors.callMethodWithArgs(reference, _retainAllId, + JniCallType.booleanType, [(elements as JObject).reference]).boolean; + return; + } + return super.retainAll(elements); + } + + @override + $E? lookup(Object? element) { + if (contains(element)) return element as $E; + return null; + } + + @override + JSet<$E> toSet() { + return toJSet(E); + } +} + +extension ToJavaSet on Iterable { + JSet toJSet(JObjType type) { + final set = JSet.hash(type); + set.addAll(this); + return set; + } +} diff --git a/pkgs/jni/lib/src/util/util.dart b/pkgs/jni/lib/src/util/util.dart new file mode 100644 index 000000000..d0a0dc503 --- /dev/null +++ b/pkgs/jni/lib/src/util/util.dart @@ -0,0 +1,8 @@ +// Copyright (c) 2023, 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. + +export 'jiterator.dart'; +export 'jlist.dart'; +export 'jmap.dart'; +export 'jset.dart'; diff --git a/pkgs/jni/linux/CMakeLists.txt b/pkgs/jni/linux/CMakeLists.txt new file mode 100644 index 000000000..953cb0f7f --- /dev/null +++ b/pkgs/jni/linux/CMakeLists.txt @@ -0,0 +1,22 @@ +# The Flutter tooling requires that developers have CMake 3.10 or later +# installed. You should not increase this version, as doing so will cause +# the plugin to fail to compile for some customers of the plugin. +cmake_minimum_required(VERSION 3.10) + +# Project-level configuration. +set(PROJECT_NAME "jni") +project(${PROJECT_NAME} LANGUAGES CXX) + +# Invoke the build for native code shared with the other target platforms. +# This can be changed to accomodate different builds. +add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../src" "${CMAKE_CURRENT_BINARY_DIR}/shared") + +# List of absolute paths to libraries that should be bundled with the plugin. +# This list could contain prebuilt libraries, or libraries created by an +# external build triggered from this build file. +set(jni_bundled_libraries + # Defined in ../src/CMakeLists.txt. + # This can be changed to accomodate different builds. + $ + PARENT_SCOPE +) diff --git a/pkgs/jni/macos/Classes/jni.c b/pkgs/jni/macos/Classes/jni.c new file mode 100644 index 000000000..28e68ae51 --- /dev/null +++ b/pkgs/jni/macos/Classes/jni.c @@ -0,0 +1,3 @@ +// Relative import to be able to reuse the C sources. +// See the comment in ../{projectName}}.podspec for more information. +#include "../../src/jni.c" diff --git a/pkgs/jni/macos/jni.podspec b/pkgs/jni/macos/jni.podspec new file mode 100644 index 000000000..582861a93 --- /dev/null +++ b/pkgs/jni/macos/jni.podspec @@ -0,0 +1,27 @@ +# +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. +# Run `pod lib lint jni.podspec` to validate before publishing. +# +Pod::Spec.new do |s| + s.name = 'jni' + s.version = '0.0.1' + s.summary = 'A new Flutter FFI plugin project.' + s.description = <<-DESC +A new Flutter FFI plugin project. + DESC + s.homepage = 'http://example.com' + s.license = { :file => '../LICENSE' } + s.author = { 'Your Company' => 'email@example.com' } + + # This will ensure the source files in Classes/ are included in the native + # builds of apps using this FFI plugin. Podspec does not support relative + # paths, so Classes contains a forwarder C file that relatively imports + # `../src/*` so that the C sources can be shared among all target platforms. + s.source = { :path => '.' } + s.source_files = 'Classes/**/*' + s.dependency 'FlutterMacOS' + + s.platform = :osx, '10.11' + s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' } + s.swift_version = '5.0' +end diff --git a/pkgs/jni/pubspec.yaml b/pkgs/jni/pubspec.yaml new file mode 100644 index 000000000..6efae3d66 --- /dev/null +++ b/pkgs/jni/pubspec.yaml @@ -0,0 +1,47 @@ +# 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. + +name: jni +description: A library to access JNI from Dart and Flutter that acts as a support library for package:jnigen. +version: 0.8.0-wip +repository: https://github.com/dart-lang/jnigen/tree/main/jni + +topics: + - interop + - ffi + - java + - kotlin + - jni + +environment: + sdk: '>=3.1.0 <4.0.0' + flutter: '>=2.11.0' + +dependencies: + collection: ^1.0.0 + plugin_platform_interface: ^2.0.2 + ffi: ^2.0.1 + path: ^1.8.0 + package_config: ^2.1.0 + args: ^2.3.1 + +dev_dependencies: + ## Pin ffigen version because we are depending on internal APIs. + ffigen: 8.0.2 + flutter_lints: ^2.0.0 + test: ^1.21.1 + logging: ^1.1.1 + +# The following section is specific to Flutter packages. +flutter: + plugin: + platforms: + linux: + ffiPlugin: true + windows: + ffiPlugin: true + android: + ffiPlugin: true + package: com.github.dart_lang.jni + pluginClass: JniPlugin diff --git a/pkgs/jni/src/.clang-format b/pkgs/jni/src/.clang-format new file mode 100644 index 000000000..a256c2f09 --- /dev/null +++ b/pkgs/jni/src/.clang-format @@ -0,0 +1,15 @@ +# From dart SDK: https://github.com/dart-lang/sdk/blob/main/.clang-format + +# Defines the Chromium style for automatic reformatting. +# http://clang.llvm.org/docs/ClangFormatStyleOptions.html +BasedOnStyle: Chromium + +# clang-format doesn't seem to do a good job of this for longer comments. +ReflowComments: 'false' + +# We have lots of these. Though we need to put them all in curly braces, +# clang-format can't do that. +AllowShortIfStatementsOnASingleLine: 'true' + +# Put escaped newlines into the rightmost column. +AlignEscapedNewlinesLeft: false diff --git a/pkgs/jni/src/.gitignore b/pkgs/jni/src/.gitignore new file mode 100644 index 000000000..cf9756bc9 --- /dev/null +++ b/pkgs/jni/src/.gitignore @@ -0,0 +1,8 @@ +CMakeFiles/ +Makefile +cmake_install.cmake +libdartjni.so +CMakeCache.txt +.cache +compile_commands.json +!.clang-format diff --git a/pkgs/jni/src/CMakeLists.txt b/pkgs/jni/src/CMakeLists.txt new file mode 100644 index 000000000..2cdb3f724 --- /dev/null +++ b/pkgs/jni/src/CMakeLists.txt @@ -0,0 +1,35 @@ +# jni_native_build (Build with jni:setup. Do not delete this line.) + +# The Flutter tooling requires that developers have CMake 3.10 or later +# installed. You should not increase this version, as doing so will cause +# the plugin to fail to compile for some customers of the plugin. +cmake_minimum_required(VERSION 3.10) + +project(jni_library VERSION 0.0.1 LANGUAGES C) + +add_library(jni SHARED + "dartjni.c" + "third_party/global_jni_env.c" + "include/dart_api_dl.c" +) + +set_target_properties(jni PROPERTIES + PUBLIC_HEADER dartjni.h + OUTPUT_NAME "dartjni" +) + +target_compile_definitions(jni PUBLIC DART_SHARED_LIB) + +if(WIN32) + set_target_properties(${TARGET_NAME} PROPERTIES + LINK_FLAGS "/DELAYLOAD:jvm.dll") +endif() + +if (ANDROID) + target_link_libraries(jni log) +else() + find_package(Java REQUIRED) + find_package(JNI REQUIRED) + include_directories(${JNI_INCLUDE_DIRS}) + target_link_libraries(jni ${JNI_LIBRARIES}) +endif() diff --git a/pkgs/jni/src/README.md b/pkgs/jni/src/README.md new file mode 100644 index 000000000..6516f65e7 --- /dev/null +++ b/pkgs/jni/src/README.md @@ -0,0 +1,5 @@ +Native code for jni library. + +## LSP instructions + +see https://releases.llvm.org/8.0.0/tools/clang/tools/extra/docs/clangd/Installation.html#project-setup for creating compile_commands.json for use with LSP based editor plugins (in VS Code, VIM etc..). \ No newline at end of file diff --git a/pkgs/jni/src/dartjni.c b/pkgs/jni/src/dartjni.c new file mode 100644 index 000000000..7c5951bc5 --- /dev/null +++ b/pkgs/jni/src/dartjni.c @@ -0,0 +1,749 @@ +// 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. + +#include +#include +#include + +#include "dartjni.h" + +#include "include/dart_api_dl.h" + +void initAllLocks(JniLocks* locks) { + init_lock(&locks->classLoadingLock); + init_lock(&locks->fieldLoadingLock); + init_lock(&locks->methodLoadingLock); +} + +/// Stores class and method references for obtaining exception details +typedef struct JniExceptionMethods { + jclass objectClass, exceptionClass, printStreamClass; + jclass byteArrayOutputStreamClass; + jmethodID toStringMethod, printStackTraceMethod; + jmethodID byteArrayOutputStreamCtor, printStreamCtor; +} JniExceptionMethods; + +// Context and shared global state. Initialized once or if thread-local, initialized once in a thread. +JniContext jni_context = { + .jvm = NULL, + .classLoader = NULL, + .loadClassMethod = NULL, + .appContext = NULL, + .currentActivity = NULL, +}; + +JniContext* jni = &jni_context; + +thread_local JNIEnv* jniEnv = NULL; + +JniExceptionMethods exceptionMethods; + +void initExceptionHandling(JniExceptionMethods* methods) { + methods->objectClass = FindClass("java/lang/Object"); + methods->exceptionClass = FindClass("java/lang/Exception"); + methods->printStreamClass = FindClass("java/io/PrintStream"); + methods->byteArrayOutputStreamClass = + FindClass("java/io/ByteArrayOutputStream"); + load_method(methods->objectClass, &methods->toStringMethod, "toString", + "()Ljava/lang/String;"); + load_method(methods->exceptionClass, &methods->printStackTraceMethod, + "printStackTrace", "(Ljava/io/PrintStream;)V"); + load_method(methods->byteArrayOutputStreamClass, + &methods->byteArrayOutputStreamCtor, "", "()V"); + load_method(methods->printStreamClass, &methods->printStreamCtor, "", + "(Ljava/io/OutputStream;)V"); +} + +/// Get JVM associated with current process. +/// Returns NULL if no JVM is running. +FFI_PLUGIN_EXPORT +JavaVM* GetJavaVM() { + return jni_context.jvm; +} + +FFI_PLUGIN_EXPORT +jclass FindClass(const char* name) { + jclass cls = NULL; + attach_thread(); + load_class_global_ref(&cls, name); + return cls; +}; + +// Android specifics + +FFI_PLUGIN_EXPORT +jobject GetClassLoader() { + attach_thread(); + return (*jniEnv)->NewGlobalRef(jniEnv, jni_context.classLoader); +} + +FFI_PLUGIN_EXPORT +jobject GetApplicationContext() { + attach_thread(); + return (*jniEnv)->NewGlobalRef(jniEnv, jni_context.appContext); +} + +FFI_PLUGIN_EXPORT +jobject GetCurrentActivity() { + attach_thread(); + return (*jniEnv)->NewGlobalRef(jniEnv, jni_context.currentActivity); +} + +// JNI Initialization + +#ifdef __ANDROID__ +JNIEXPORT void JNICALL +Java_com_github_dart_1lang_jni_JniPlugin_initializeJni(JNIEnv* env, + jobject obj, + jobject appContext, + jobject classLoader) { + jniEnv = env; + (*env)->GetJavaVM(env, &jni_context.jvm); + jni_context.classLoader = (*env)->NewGlobalRef(env, classLoader); + jni_context.appContext = (*env)->NewGlobalRef(env, appContext); + jclass classLoaderClass = (*env)->GetObjectClass(env, classLoader); + jni_context.loadClassMethod = + (*env)->GetMethodID(env, classLoaderClass, "loadClass", + "(Ljava/lang/String;)Ljava/lang/Class;"); + initAllLocks(&jni_context.locks); + initExceptionHandling(&exceptionMethods); +} + +JNIEXPORT void JNICALL +Java_com_github_dart_1lang_jni_JniPlugin_setJniActivity(JNIEnv* env, + jobject obj, + jobject activity, + jobject context) { + jniEnv = env; + if (jni_context.currentActivity != NULL) { + (*env)->DeleteGlobalRef(env, jni_context.currentActivity); + } + jni_context.currentActivity = (*env)->NewGlobalRef(env, activity); + if (jni_context.appContext != NULL) { + (*env)->DeleteGlobalRef(env, jni_context.appContext); + } + jni_context.appContext = (*env)->NewGlobalRef(env, context); +} + +// Sometimes you may get linker error trying to link JNI_CreateJavaVM APIs +// on Android NDK. So IFDEF is required. +#else +#ifdef _WIN32 +// Pre-initialization of critical section on windows - this is required because +// there's no coordination between multiple isolates calling Spawn. +// +// Taken from https://stackoverflow.com/a/12858955 +CRITICAL_SECTION spawnLock = {0}; +BOOL WINAPI DllMain(HINSTANCE hinstDLL, // handle to DLL module + DWORD fdwReason, // reason for calling function + LPVOID lpReserved) { // reserved + switch (fdwReason) { + case DLL_PROCESS_ATTACH: + // Initialize once for each new process. + // Return FALSE to fail DLL load. + InitializeCriticalSection(&spawnLock); + break; + case DLL_PROCESS_DETACH: + // Perform any necessary cleanup. + DeleteCriticalSection(&spawnLock); + break; + } + return TRUE; // Successful DLL_PROCESS_ATTACH. +} +#else +pthread_mutex_t spawnLock = PTHREAD_MUTEX_INITIALIZER; +#endif +FFI_PLUGIN_EXPORT +int SpawnJvm(JavaVMInitArgs* initArgs) { + if (jni_context.jvm != NULL) { + return DART_JNI_SINGLETON_EXISTS; + } + + acquire_lock(&spawnLock); + // Init may have happened in the meanwhile. + if (jni_context.jvm != NULL) { + release_lock(&spawnLock); + return DART_JNI_SINGLETON_EXISTS; + } + JavaVMOption jvmopt[1]; + char class_path[] = "-Djava.class.path=."; + jvmopt[0].optionString = class_path; + JavaVMInitArgs vmArgs; + if (!initArgs) { + vmArgs.version = JNI_VERSION_1_6; + vmArgs.nOptions = 1; + vmArgs.options = jvmopt; + vmArgs.ignoreUnrecognized = JNI_TRUE; + initArgs = &vmArgs; + } + const long flag = + JNI_CreateJavaVM(&jni_context.jvm, __ENVP_CAST & jniEnv, initArgs); + if (flag != JNI_OK) { + return flag; + } + initAllLocks(&jni_context.locks); + initExceptionHandling(&exceptionMethods); + release_lock(&spawnLock); + + return JNI_OK; +} +#endif + +// accessors - a bunch of functions which are directly called by jnigen generated bindings +// and also package:jni reflective method access. + +JniClassLookupResult getClass(char* internalName) { + JniClassLookupResult result = {NULL, NULL}; + result.value = FindClass(internalName); + result.exception = check_exception(); + return result; +} + +typedef void* (*MemberGetter)(JNIEnv* env, jclass clazz, char* name, char* sig); + +static inline JniPointerResult _getId(MemberGetter getter, + jclass cls, + char* name, + char* sig) { + JniPointerResult result = {NULL, NULL}; + attach_thread(); + result.value = getter(jniEnv, cls, name, sig); + result.exception = check_exception(); + return result; +} + +JniPointerResult getMethodID(jclass cls, char* name, char* sig) { + return _getId((MemberGetter)(*jniEnv)->GetMethodID, cls, name, sig); +} + +JniPointerResult getStaticMethodID(jclass cls, char* name, char* sig) { + return _getId((MemberGetter)(*jniEnv)->GetStaticMethodID, cls, name, sig); +} + +JniPointerResult getFieldID(jclass cls, char* name, char* sig) { + return _getId((MemberGetter)(*jniEnv)->GetFieldID, cls, name, sig); +} + +JniPointerResult getStaticFieldID(jclass cls, char* name, char* sig) { + return _getId((MemberGetter)(*jniEnv)->GetStaticFieldID, cls, name, sig); +} + +JniResult callMethod(jobject obj, + jmethodID fieldID, + int callType, + jvalue* args) { + attach_thread(); + jvalue result = {.j = 0}; + switch (callType) { + case booleanType: + result.z = (*jniEnv)->CallBooleanMethodA(jniEnv, obj, fieldID, args); + break; + case byteType: + result.b = (*jniEnv)->CallByteMethodA(jniEnv, obj, fieldID, args); + break; + case shortType: + result.s = (*jniEnv)->CallShortMethodA(jniEnv, obj, fieldID, args); + break; + case charType: + result.c = (*jniEnv)->CallCharMethodA(jniEnv, obj, fieldID, args); + break; + case intType: + result.i = (*jniEnv)->CallIntMethodA(jniEnv, obj, fieldID, args); + break; + case longType: + result.j = (*jniEnv)->CallLongMethodA(jniEnv, obj, fieldID, args); + break; + case floatType: + result.f = (*jniEnv)->CallFloatMethodA(jniEnv, obj, fieldID, args); + break; + case doubleType: + result.d = (*jniEnv)->CallDoubleMethodA(jniEnv, obj, fieldID, args); + break; + case objectType: + result.l = (*jniEnv)->CallObjectMethodA(jniEnv, obj, fieldID, args); + break; + case voidType: + (*jniEnv)->CallVoidMethodA(jniEnv, obj, fieldID, args); + break; + } + jthrowable exception = check_exception(); + if (callType == objectType && exception == NULL) { + result.l = to_global_ref(result.l); + } + JniResult jniResult = {.value = result, .exception = exception}; + return jniResult; +} + +// TODO(#60): Any way to reduce this boilerplate? +JniResult callStaticMethod(jclass cls, + jmethodID methodID, + int callType, + jvalue* args) { + attach_thread(); + jvalue result = {.j = 0}; + switch (callType) { + case booleanType: + result.z = + (*jniEnv)->CallStaticBooleanMethodA(jniEnv, cls, methodID, args); + break; + case byteType: + result.b = (*jniEnv)->CallStaticByteMethodA(jniEnv, cls, methodID, args); + break; + case shortType: + result.s = (*jniEnv)->CallStaticShortMethodA(jniEnv, cls, methodID, args); + break; + case charType: + result.c = (*jniEnv)->CallStaticCharMethodA(jniEnv, cls, methodID, args); + break; + case intType: + result.i = (*jniEnv)->CallStaticIntMethodA(jniEnv, cls, methodID, args); + break; + case longType: + result.j = (*jniEnv)->CallStaticLongMethodA(jniEnv, cls, methodID, args); + break; + case floatType: + result.f = (*jniEnv)->CallStaticFloatMethodA(jniEnv, cls, methodID, args); + break; + case doubleType: + result.d = + (*jniEnv)->CallStaticDoubleMethodA(jniEnv, cls, methodID, args); + break; + case objectType: + result.l = + (*jniEnv)->CallStaticObjectMethodA(jniEnv, cls, methodID, args); + break; + case voidType: + (*jniEnv)->CallStaticVoidMethodA(jniEnv, cls, methodID, args); + break; + } + jthrowable exception = check_exception(); + if (callType == objectType && exception == NULL) { + result.l = to_global_ref(result.l); + } + JniResult jniResult = {.value = result, .exception = exception}; + return jniResult; +} + +JniResult getField(jobject obj, jfieldID fieldID, int callType) { + attach_thread(); + jvalue result = {.j = 0}; + switch (callType) { + case booleanType: + result.z = (*jniEnv)->GetBooleanField(jniEnv, obj, fieldID); + break; + case byteType: + result.b = (*jniEnv)->GetByteField(jniEnv, obj, fieldID); + break; + case shortType: + result.s = (*jniEnv)->GetShortField(jniEnv, obj, fieldID); + break; + case charType: + result.c = (*jniEnv)->GetCharField(jniEnv, obj, fieldID); + break; + case intType: + result.i = (*jniEnv)->GetIntField(jniEnv, obj, fieldID); + break; + case longType: + result.j = (*jniEnv)->GetLongField(jniEnv, obj, fieldID); + break; + case floatType: + result.f = (*jniEnv)->GetFloatField(jniEnv, obj, fieldID); + break; + case doubleType: + result.d = (*jniEnv)->GetDoubleField(jniEnv, obj, fieldID); + break; + case objectType: + result.l = (*jniEnv)->GetObjectField(jniEnv, obj, fieldID); + break; + case voidType: + // This error should have been handled in Dart. + break; + } + jthrowable exception = check_exception(); + if (callType == objectType && exception == NULL) { + result.l = to_global_ref(result.l); + } + JniResult jniResult = {.value = result, .exception = exception}; + return jniResult; +} + +FFI_PLUGIN_EXPORT +JniResult getStaticField(jclass cls, jfieldID fieldID, int callType) { + attach_thread(); + jvalue result = {.j = 0}; + switch (callType) { + case booleanType: + result.z = (*jniEnv)->GetStaticBooleanField(jniEnv, cls, fieldID); + break; + case byteType: + result.b = (*jniEnv)->GetStaticByteField(jniEnv, cls, fieldID); + break; + case shortType: + result.s = (*jniEnv)->GetStaticShortField(jniEnv, cls, fieldID); + break; + case charType: + result.c = (*jniEnv)->GetStaticCharField(jniEnv, cls, fieldID); + break; + case intType: + result.i = (*jniEnv)->GetStaticIntField(jniEnv, cls, fieldID); + break; + case longType: + result.j = (*jniEnv)->GetStaticLongField(jniEnv, cls, fieldID); + break; + case floatType: + result.f = (*jniEnv)->GetStaticFloatField(jniEnv, cls, fieldID); + break; + case doubleType: + result.d = (*jniEnv)->GetStaticDoubleField(jniEnv, cls, fieldID); + break; + case objectType: + result.l = (*jniEnv)->GetStaticObjectField(jniEnv, cls, fieldID); + break; + case voidType: + // This error should have been handled in dart. + // is there a way to mark this as unreachable? + // or throw exception in Dart using Dart's C API. + break; + } + jthrowable exception = check_exception(); + if (callType == objectType && exception == NULL) { + result.l = to_global_ref(result.l); + } + JniResult jniResult = {.value = result, .exception = exception}; + return jniResult; +} + +JniResult newObject(jclass cls, jmethodID ctor, jvalue* args) { + attach_thread(); + jobject result = (*jniEnv)->NewObjectA(jniEnv, cls, ctor, args); + return to_global_ref_result(result); +} + +JniResult newPrimitiveArray(jsize length, int type) { + attach_thread(); + jarray array; + switch (type) { + case booleanType: + array = (*jniEnv)->NewBooleanArray(jniEnv, length); + break; + case byteType: + array = (*jniEnv)->NewByteArray(jniEnv, length); + break; + case shortType: + array = (*jniEnv)->NewShortArray(jniEnv, length); + break; + case charType: + array = (*jniEnv)->NewCharArray(jniEnv, length); + break; + case intType: + array = (*jniEnv)->NewIntArray(jniEnv, length); + break; + case longType: + array = (*jniEnv)->NewLongArray(jniEnv, length); + break; + case floatType: + array = (*jniEnv)->NewFloatArray(jniEnv, length); + break; + case doubleType: + array = (*jniEnv)->NewDoubleArray(jniEnv, length); + break; + case objectType: + case voidType: + // This error should have been handled in dart. + // is there a way to mark this as unreachable? + // or throw exception in Dart using Dart's C API. + break; + } + return to_global_ref_result(array); +} + +JniResult newObjectArray(jsize length, + jclass elementClass, + jobject initialElement) { + attach_thread(); + jarray array = + (*jniEnv)->NewObjectArray(jniEnv, length, elementClass, initialElement); + return to_global_ref_result(array); +} + +JniResult getArrayElement(jarray array, int index, int type) { + JniResult result = {{.l = NULL}, NULL}; + attach_thread(); + jvalue value; + switch (type) { + case booleanType: + (*jniEnv)->GetBooleanArrayRegion(jniEnv, array, index, 1, &value.z); + break; + case byteType: + (*jniEnv)->GetByteArrayRegion(jniEnv, array, index, 1, &value.b); + break; + case shortType: + (*jniEnv)->GetShortArrayRegion(jniEnv, array, index, 1, &value.s); + break; + case charType: + (*jniEnv)->GetCharArrayRegion(jniEnv, array, index, 1, &value.c); + break; + case intType: + (*jniEnv)->GetIntArrayRegion(jniEnv, array, index, 1, &value.i); + break; + case longType: + (*jniEnv)->GetLongArrayRegion(jniEnv, array, index, 1, &value.j); + break; + case floatType: + (*jniEnv)->GetFloatArrayRegion(jniEnv, array, index, 1, &value.f); + break; + case doubleType: + (*jniEnv)->GetDoubleArrayRegion(jniEnv, array, index, 1, &value.d); + break; + case objectType: + value.l = (*jniEnv)->GetObjectArrayElement(jniEnv, array, index); + case voidType: + // This error should have been handled in dart. + // is there a way to mark this as unreachable? + // or throw exception in Dart using Dart's C API. + break; + } + jthrowable exception = check_exception(); + if (type == objectType && exception == NULL) { + value.l = to_global_ref(value.l); + } + JniResult jniResult = {.value = value, .exception = exception}; + return jniResult; +} + +JniExceptionDetails getExceptionDetails(jthrowable exception) { + JniExceptionDetails details; + details.message = (*jniEnv)->CallObjectMethod( + jniEnv, exception, exceptionMethods.toStringMethod); + jobject buffer = + (*jniEnv)->NewObject(jniEnv, exceptionMethods.byteArrayOutputStreamClass, + exceptionMethods.byteArrayOutputStreamCtor); + jobject printStream = + (*jniEnv)->NewObject(jniEnv, exceptionMethods.printStreamClass, + exceptionMethods.printStreamCtor, buffer); + (*jniEnv)->CallVoidMethod( + jniEnv, exception, exceptionMethods.printStackTraceMethod, printStream); + details.stacktrace = (*jniEnv)->CallObjectMethod( + jniEnv, buffer, exceptionMethods.toStringMethod); + details.message = to_global_ref(details.message); + details.stacktrace = to_global_ref(details.stacktrace); + return details; +} + +JniAccessorsStruct accessors = { + .getClass = getClass, + .getFieldID = getFieldID, + .getStaticFieldID = getStaticFieldID, + .getMethodID = getMethodID, + .getStaticMethodID = getStaticMethodID, + .newObject = newObject, + .newPrimitiveArray = newPrimitiveArray, + .newObjectArray = newObjectArray, + .getArrayElement = getArrayElement, + .callMethod = callMethod, + .callStaticMethod = callStaticMethod, + .getField = getField, + .getStaticField = getStaticField, + .getExceptionDetails = getExceptionDetails, +}; + +FFI_PLUGIN_EXPORT JniAccessorsStruct* GetAccessors() { + return &accessors; +} + +// These will not be required after migrating to Dart-only bindings. +FFI_PLUGIN_EXPORT JniContext* GetJniContextPtr() { + return jni; +} + +FFI_PLUGIN_EXPORT JNIEnv* GetJniEnv() { + if (jni_context.jvm == NULL) { + return NULL; + } + attach_thread(); + return jniEnv; +} + +FFI_PLUGIN_EXPORT intptr_t InitDartApiDL(void* data) { + return Dart_InitializeApiDL(data); +} + +// com.github.dart_lang.jni.DartException +jclass _c_DartException = NULL; + +jmethodID _m_DartException__ctor = NULL; +FFI_PLUGIN_EXPORT JniResult DartException__ctor(jstring message) { + attach_thread(); + load_class_global_ref(&_c_DartException, + "com/github/dart_lang/jni/PortProxy$DartException"); + if (_c_DartException == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_DartException, &_m_DartException__ctor, "", + "(Ljava/lang/String;)V"); + if (_m_DartException__ctor == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject(jniEnv, _c_DartException, + _m_DartException__ctor, message); + jthrowable exception = check_exception(); + if (exception == NULL) { + _result = to_global_ref(_result); + } + return (JniResult){.value = {.l = _result}, .exception = check_exception()}; +} + +JNIEXPORT void JNICALL +Java_com_github_dart_1lang_jni_PortContinuation__1resumeWith(JNIEnv* env, + jclass clazz, + jlong port, + jobject result) { + attach_thread(); + Dart_CObject c_post; + c_post.type = Dart_CObject_kInt64; + c_post.value.as_int64 = (jlong)((*env)->NewGlobalRef(env, result)); + Dart_PostCObject_DL(port, &c_post); +} + +// com.github.dart_lang.jni.PortContinuation +jclass _c_PortContinuation = NULL; + +jmethodID _m_PortContinuation__ctor = NULL; +FFI_PLUGIN_EXPORT +JniResult PortContinuation__ctor(int64_t j) { + attach_thread(); + load_class_global_ref(&_c_PortContinuation, + "com/github/dart_lang/jni/PortContinuation"); + if (_c_PortContinuation == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PortContinuation, &_m_PortContinuation__ctor, "", + "(J)V"); + if (_m_PortContinuation__ctor == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject(jniEnv, _c_PortContinuation, + _m_PortContinuation__ctor, j); + jthrowable exception = check_exception(); + if (exception == NULL) { + _result = to_global_ref(_result); + } + return (JniResult){.value = {.l = _result}, .exception = check_exception()}; +} + +// com.github.dart_lang.jni.PortProxy +jclass _c_PortProxy = NULL; + +jmethodID _m_PortProxy__newInstance = NULL; +FFI_PLUGIN_EXPORT +JniResult PortProxy__newInstance(jobject binaryName, + int64_t port, + int64_t functionPtr) { + attach_thread(); + load_class_global_ref(&_c_PortProxy, "com/github/dart_lang/jni/PortProxy"); + if (_c_PortProxy == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_PortProxy, &_m_PortProxy__newInstance, "newInstance", + "(Ljava/lang/String;JJJ)Ljava/lang/Object;"); + if (_m_PortProxy__newInstance == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_PortProxy, _m_PortProxy__newInstance, binaryName, port, + (jlong)Dart_CurrentIsolate_DL(), functionPtr); + return to_global_ref_result(_result); +} + +FFI_PLUGIN_EXPORT +void resultFor(CallbackResult* result, jobject object) { + acquire_lock(&result->lock); + result->ready = 1; + result->object = object; + signal_cond(&result->cond); + release_lock(&result->lock); +} + +jclass _c_Object = NULL; +jclass _c_Long = NULL; + +jmethodID _m_Long_init = NULL; + +JNIEXPORT jobjectArray JNICALL +Java_com_github_dart_1lang_jni_PortProxy__1invoke(JNIEnv* env, + jclass clazz, + jlong port, + jlong isolateId, + jlong functionPtr, + jobject proxy, + jstring methodDescriptor, + jobjectArray args) { + CallbackResult* result = (CallbackResult*)malloc(sizeof(CallbackResult)); + if (isolateId != (jlong)Dart_CurrentIsolate_DL()) { + init_lock(&result->lock); + init_cond(&result->cond); + acquire_lock(&result->lock); + result->ready = 0; + result->object = NULL; + + Dart_CObject c_result; + c_result.type = Dart_CObject_kInt64; + c_result.value.as_int64 = (jlong)result; + + Dart_CObject c_method; + c_method.type = Dart_CObject_kInt64; + c_method.value.as_int64 = + (jlong)((*env)->NewGlobalRef(env, methodDescriptor)); + + Dart_CObject c_args; + c_args.type = Dart_CObject_kInt64; + c_args.value.as_int64 = (jlong)((*env)->NewGlobalRef(env, args)); + + Dart_CObject* c_post_arr[] = {&c_result, &c_method, &c_args}; + Dart_CObject c_post; + c_post.type = Dart_CObject_kArray; + c_post.value.as_array.values = c_post_arr; + c_post.value.as_array.length = sizeof(c_post_arr) / sizeof(c_post_arr[0]); + + Dart_PostCObject_DL(port, &c_post); + + while (!result->ready) { + wait_for(&result->cond, &result->lock); + } + + release_lock(&result->lock); + destroy_lock(&result->lock); + destroy_cond(&result->cond); + } else { + result->object = ((jobject(*)(uint64_t, jobject, jobject))functionPtr)( + port, (*env)->NewGlobalRef(env, methodDescriptor), + (*env)->NewGlobalRef(env, args)); + } + // Returning an array of length 2. + // [0]: The result pointer, used for cleaning up the global reference, and + // freeing the memory since we passed the ownership to Java. + // [1]: The returned object. + attach_thread(); + load_class_global_ref(&_c_Object, "java/lang/Object"); + load_class_global_ref(&_c_Long, "java/lang/Long"); + load_method(_c_Long, &_m_Long_init, "", "(J)V"); + jobject first = (*env)->NewObject(env, _c_Long, _m_Long_init, (jlong)result); + jobject second = result->object; + jobjectArray arr = (*env)->NewObjectArray(env, 2, _c_Object, NULL); + (*env)->SetObjectArrayElement(env, arr, 0, first); + (*env)->SetObjectArrayElement(env, arr, 1, second); + return arr; +} + +JNIEXPORT void JNICALL +Java_com_github_dart_1lang_jni_PortProxy__1cleanUp(JNIEnv* env, + jclass clazz, + jlong resultPtr) { + CallbackResult* result = (CallbackResult*)resultPtr; + (*env)->DeleteGlobalRef(env, result->object); + free(result); +} + +JNIEXPORT void JNICALL +Java_com_github_dart_1lang_jni_PortCleaner_clean(JNIEnv* env, + jclass clazz, + jlong port) { + Dart_CObject close_signal; + close_signal.type = Dart_CObject_kNull; + Dart_PostCObject_DL(port, &close_signal); +} diff --git a/pkgs/jni/src/dartjni.h b/pkgs/jni/src/dartjni.h new file mode 100644 index 000000000..8f1dc7481 --- /dev/null +++ b/pkgs/jni/src/dartjni.h @@ -0,0 +1,424 @@ +// 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. + +#pragma once + +// Note: include appropriate system jni.h as found by CMake, not third_party/jni.h. +#include +#include +#include +#include + +#if _WIN32 +#include +#else +#include +#include +#endif + +#if _WIN32 +#define FFI_PLUGIN_EXPORT __declspec(dllexport) +#else +#define FFI_PLUGIN_EXPORT +#endif + +#if defined _WIN32 +#define thread_local __declspec(thread) +#else +#define thread_local __thread +#endif + +#ifdef __ANDROID__ +#include +#endif + +#ifdef __ANDROID__ +#define __ENVP_CAST (JNIEnv**) +#else +#define __ENVP_CAST (void**) +#endif + +/// Locking functions for windows and pthread. + +#if defined _WIN32 +#include + +typedef CRITICAL_SECTION MutexLock; +typedef CONDITION_VARIABLE ConditionVariable; + +static inline void init_lock(MutexLock* lock) { + InitializeCriticalSection(lock); +} + +static inline void acquire_lock(MutexLock* lock) { + EnterCriticalSection(lock); +} + +static inline void release_lock(MutexLock* lock) { + LeaveCriticalSection(lock); +} + +static inline void destroy_lock(MutexLock* lock) { + DeleteCriticalSection(lock); +} + +static inline void init_cond(ConditionVariable* cond) { + InitializeConditionVariable(cond); +} + +static inline void signal_cond(ConditionVariable* cond) { + WakeConditionVariable(cond); +} + +static inline void wait_for(ConditionVariable* cond, MutexLock* lock) { + SleepConditionVariableCS(cond, lock, INFINITE); +} + +static inline void destroy_cond(ConditionVariable* cond) { + // Not available. +} + +#elif defined __APPLE__ || defined __LINUX__ || defined __ANDROID__ || \ + defined __GNUC__ +#include + +typedef pthread_mutex_t MutexLock; +typedef pthread_cond_t ConditionVariable; + +static inline void init_lock(MutexLock* lock) { + pthread_mutex_init(lock, NULL); +} + +static inline void acquire_lock(MutexLock* lock) { + pthread_mutex_lock(lock); +} + +static inline void release_lock(MutexLock* lock) { + pthread_mutex_unlock(lock); +} + +static inline void destroy_lock(MutexLock* lock) { + pthread_mutex_destroy(lock); +} + +static inline void init_cond(ConditionVariable* cond) { + pthread_cond_init(cond, NULL); +} + +static inline void signal_cond(ConditionVariable* cond) { + pthread_cond_signal(cond); +} + +static inline void wait_for(ConditionVariable* cond, MutexLock* lock) { + pthread_cond_wait(cond, lock); +} + +static inline void destroy_cond(ConditionVariable* cond) { + pthread_cond_destroy(cond); +} + +#else + +#error "No locking/condition variable support; Possibly unsupported platform" + +#endif + +typedef struct CallbackResult { + MutexLock lock; + ConditionVariable cond; + int ready; + jobject object; +} CallbackResult; + +typedef struct JniLocks { + MutexLock classLoadingLock; + MutexLock methodLoadingLock; + MutexLock fieldLoadingLock; +} JniLocks; + +/// Represents the error when dart-jni layer has already spawned singleton VM. +#define DART_JNI_SINGLETON_EXISTS (-99); + +/// Stores the global state of the JNI. +typedef struct JniContext { + JavaVM* jvm; + jobject classLoader; + jmethodID loadClassMethod; + jobject currentActivity; + jobject appContext; + JniLocks locks; +} JniContext; + +// jniEnv for this thread, used by inline functions in this header, +// therefore declared as extern. +extern thread_local JNIEnv* jniEnv; + +extern JniContext* jni; + +/// Types used by JNI API to distinguish between primitive types. +enum JniType { + booleanType = 0, + byteType = 1, + shortType = 2, + charType = 3, + intType = 4, + longType = 5, + floatType = 6, + doubleType = 7, + objectType = 8, + voidType = 9, +}; + +/// Result type for use by JNI. +/// +/// If [exception] is null, it means the result is valid. +/// It's assumed that the caller knows the expected type in [result]. +typedef struct JniResult { + jvalue value; + jthrowable exception; +} JniResult; + +/// Similar to [JniResult] but for class lookups. +typedef struct JniClassLookupResult { + jclass value; + jthrowable exception; +} JniClassLookupResult; + +/// Similar to [JniResult] but for method/field ID lookups. +typedef struct JniPointerResult { + const void* value; + jthrowable exception; +} JniPointerResult; + +/// JniExceptionDetails holds 2 jstring objects, one is the result of +/// calling `toString` on exception object, other is stack trace; +typedef struct JniExceptionDetails { + jstring message; + jstring stacktrace; +} JniExceptionDetails; + +/// This struct contains functions which wrap method call / field access conveniently along with +/// exception checking. +/// +/// Flutter embedding checks for pending JNI exceptions before an FFI transition, which requires us +/// to check for and clear the exception before returning to dart code, which requires these functions +/// to return result types. +typedef struct JniAccessorsStruct { + JniClassLookupResult (*getClass)(char* internalName); + JniPointerResult (*getFieldID)(jclass cls, char* fieldName, char* signature); + JniPointerResult (*getStaticFieldID)(jclass cls, + char* fieldName, + char* signature); + JniPointerResult (*getMethodID)(jclass cls, + char* methodName, + char* signature); + JniPointerResult (*getStaticMethodID)(jclass cls, + char* methodName, + char* signature); + JniResult (*newObject)(jclass cls, jmethodID ctor, jvalue* args); + JniResult (*newPrimitiveArray)(jsize length, int type); + JniResult (*newObjectArray)(jsize length, + jclass elementClass, + jobject initialElement); + JniResult (*getArrayElement)(jarray array, int index, int type); + JniResult (*callMethod)(jobject obj, + jmethodID methodID, + int callType, + jvalue* args); + JniResult (*callStaticMethod)(jclass cls, + jmethodID methodID, + int callType, + jvalue* args); + JniResult (*getField)(jobject obj, jfieldID fieldID, int callType); + JniResult (*getStaticField)(jclass cls, jfieldID fieldID, int callType); + JniExceptionDetails (*getExceptionDetails)(jthrowable exception); +} JniAccessorsStruct; + +FFI_PLUGIN_EXPORT JniAccessorsStruct* GetAccessors(); + +FFI_PLUGIN_EXPORT JavaVM* GetJavaVM(void); + +FFI_PLUGIN_EXPORT JNIEnv* GetJniEnv(void); + +/// Spawn a JVM with given arguments. +/// +/// Returns JNI_OK on success, and one of the documented JNI error codes on +/// failure. It returns DART_JNI_SINGLETON_EXISTS if an attempt to spawn multiple +/// JVMs is made, even if the underlying API potentially supports multiple VMs. +FFI_PLUGIN_EXPORT int SpawnJvm(JavaVMInitArgs* args); + +/// Load class through platform-specific mechanism. +/// +/// Currently uses application classloader on android, +/// and JNIEnv->FindClass on other platforms. +FFI_PLUGIN_EXPORT jclass FindClass(const char* name); + +/// Returns Application classLoader (on Android), +/// which can be used to load application and platform classes. +/// +/// On other platforms, NULL is returned. +FFI_PLUGIN_EXPORT jobject GetClassLoader(void); + +/// Returns application context on Android. +/// +/// On other platforms, NULL is returned. +FFI_PLUGIN_EXPORT jobject GetApplicationContext(void); + +/// Returns current activity of the app on Android. +FFI_PLUGIN_EXPORT jobject GetCurrentActivity(void); + +static inline void attach_thread() { + if (jniEnv == NULL) { + (*jni->jvm)->AttachCurrentThread(jni->jvm, __ENVP_CAST & jniEnv, NULL); + } +} + +/// Load class into [cls] using platform specific mechanism +static inline void load_class_platform(jclass* cls, const char* name) { +#ifdef __ANDROID__ + jstring className = (*jniEnv)->NewStringUTF(jniEnv, name); + *cls = (*jniEnv)->CallObjectMethod(jniEnv, jni->classLoader, + jni->loadClassMethod, className); + (*jniEnv)->DeleteLocalRef(jniEnv, className); +#else + *cls = (*jniEnv)->FindClass(jniEnv, name); +#endif +} + +static inline void load_class_local_ref(jclass* cls, const char* name) { + if (*cls == NULL) { + acquire_lock(&jni->locks.classLoadingLock); + if (*cls == NULL) { + load_class_platform(cls, name); + } + release_lock(&jni->locks.classLoadingLock); + } +} + +static inline void load_class_global_ref(jclass* cls, const char* name) { + if (*cls == NULL) { + jclass tmp = NULL; + acquire_lock(&jni->locks.classLoadingLock); + if (*cls == NULL) { + load_class_platform(&tmp, name); + if (!(*jniEnv)->ExceptionCheck(jniEnv)) { + *cls = (*jniEnv)->NewGlobalRef(jniEnv, tmp); + (*jniEnv)->DeleteLocalRef(jniEnv, tmp); + } + } + release_lock(&jni->locks.classLoadingLock); + } +} + +static inline void load_method(jclass cls, + jmethodID* res, + const char* name, + const char* sig) { + if (*res == NULL) { + acquire_lock(&jni->locks.methodLoadingLock); + if (*res == NULL) { + *res = (*jniEnv)->GetMethodID(jniEnv, cls, name, sig); + } + release_lock(&jni->locks.methodLoadingLock); + } +} + +static inline void load_static_method(jclass cls, + jmethodID* res, + const char* name, + const char* sig) { + if (*res == NULL) { + acquire_lock(&jni->locks.methodLoadingLock); + if (*res == NULL) { + *res = (*jniEnv)->GetStaticMethodID(jniEnv, cls, name, sig); + } + release_lock(&jni->locks.methodLoadingLock); + } +} + +static inline void load_field(jclass cls, + jfieldID* res, + const char* name, + const char* sig) { + if (*res == NULL) { + acquire_lock(&jni->locks.fieldLoadingLock); + if (*res == NULL) { + *res = (*jniEnv)->GetFieldID(jniEnv, cls, name, sig); + } + release_lock(&jni->locks.fieldLoadingLock); + } +} + +static inline void load_static_field(jclass cls, + jfieldID* res, + const char* name, + const char* sig) { + if (*res == NULL) { + acquire_lock(&jni->locks.fieldLoadingLock); + if (*res == NULL) { + *res = (*jniEnv)->GetStaticFieldID(jniEnv, cls, name, sig); + } + release_lock(&jni->locks.fieldLoadingLock); + } +} + +static inline jobject to_global_ref(jobject ref) { + jobject g = (*jniEnv)->NewGlobalRef(jniEnv, ref); + (*jniEnv)->DeleteLocalRef(jniEnv, ref); + return g; +} + +// These functions are useful for C+Dart bindings, and not required for pure dart bindings. + +FFI_PLUGIN_EXPORT JniContext* GetJniContextPtr(); + +/// For use by jni_gen's generated code +/// don't use these. + +// these 2 fn ptr vars will be defined by generated code library +extern JniContext* (*context_getter)(void); +extern JNIEnv* (*env_getter)(void); + +// this function will be exported by generated code library +// it will set above 2 variables. +FFI_PLUGIN_EXPORT void setJniGetters(struct JniContext* (*cg)(void), + JNIEnv* (*eg)(void)); + +static inline void load_env() { + if (jniEnv == NULL) { + jni = context_getter(); + jniEnv = env_getter(); + } +} + +static inline jthrowable check_exception() { + jthrowable exception = (*jniEnv)->ExceptionOccurred(jniEnv); + if (exception != NULL) (*jniEnv)->ExceptionClear(jniEnv); + if (exception == NULL) return NULL; + return to_global_ref(exception); +} + +static inline JniResult to_global_ref_result(jobject ref) { + JniResult result; + result.exception = check_exception(); + if (result.exception == NULL) { + result.value.l = to_global_ref(ref); + } + return result; +} + +FFI_PLUGIN_EXPORT intptr_t InitDartApiDL(void* data); + +FFI_PLUGIN_EXPORT +JniResult DartException__ctor(jstring message); + +FFI_PLUGIN_EXPORT +JniResult PortContinuation__ctor(int64_t j); + +FFI_PLUGIN_EXPORT +JniResult PortProxy__newInstance(jobject binaryName, + int64_t port, + int64_t functionPtr); + +FFI_PLUGIN_EXPORT void resultFor(CallbackResult* result, jobject object); diff --git a/pkgs/jni/src/include/BUILD.gn b/pkgs/jni/src/include/BUILD.gn new file mode 100644 index 000000000..2b10262f8 --- /dev/null +++ b/pkgs/jni/src/include/BUILD.gn @@ -0,0 +1,23 @@ +# Copyright (c) 2021, 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. + +import("../../sdk_args.gni") + +# This rule copies header files to include/ +copy("copy_headers") { + visibility = [ "../../sdk:copy_headers" ] + + sources = [ + "dart_api.h", + "dart_api_dl.c", + "dart_api_dl.h", + "dart_native_api.h", + "dart_tools_api.h", + "dart_version.h", + "internal/dart_api_dl_impl.h", + ] + + outputs = + [ "$root_out_dir/$dart_sdk_output/include/{{source_target_relative}}" ] +} diff --git a/pkgs/jni/src/include/analyze_snapshot_api.h b/pkgs/jni/src/include/analyze_snapshot_api.h new file mode 100644 index 000000000..0e68d5ccb --- /dev/null +++ b/pkgs/jni/src/include/analyze_snapshot_api.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2021, 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. + */ + +#ifndef RUNTIME_INCLUDE_ANALYZE_SNAPSHOT_API_H_ +#define RUNTIME_INCLUDE_ANALYZE_SNAPSHOT_API_H_ + +#include + +namespace dart { +namespace snapshot_analyzer { +typedef struct { + const uint8_t* vm_snapshot_data; + const uint8_t* vm_snapshot_instructions; + const uint8_t* vm_isolate_data; + const uint8_t* vm_isolate_instructions; +} Dart_SnapshotAnalyzerInformation; + +void Dart_DumpSnapshotInformationAsJson(char** buffer, + intptr_t* buffer_length, + Dart_SnapshotAnalyzerInformation* info); + +void Dart_DumpSnapshotInformationPP(Dart_SnapshotAnalyzerInformation* info); + +} // namespace snapshot_analyzer +} // namespace dart + +#endif // RUNTIME_INCLUDE_ANALYZE_SNAPSHOT_API_H_ diff --git a/pkgs/jni/src/include/bin/dart_io_api.h b/pkgs/jni/src/include/bin/dart_io_api.h new file mode 100644 index 000000000..cc647976c --- /dev/null +++ b/pkgs/jni/src/include/bin/dart_io_api.h @@ -0,0 +1,69 @@ +// Copyright (c) 2015, 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. + +#ifndef RUNTIME_INCLUDE_BIN_DART_IO_API_H_ +#define RUNTIME_INCLUDE_BIN_DART_IO_API_H_ + +#include "dart_tools_api.h" + +namespace dart { +namespace bin { + +// Bootstraps 'dart:io'. +void BootstrapDartIo(); + +// Cleans up 'dart:io'. +void CleanupDartIo(); + +// Lets dart:io know where the system temporary directory is located. +// Currently only wired up on Android. +void SetSystemTempDirectory(const char* system_temp); + +// Tells the system whether to capture Stdout events. +void SetCaptureStdout(bool value); + +// Tells the system whether to capture Stderr events. +void SetCaptureStderr(bool value); + +// Should Stdout events be captured? +bool ShouldCaptureStdout(); + +// Should Stderr events be captured? +bool ShouldCaptureStderr(); + +// Set the executable name used by Platform.executable. +void SetExecutableName(const char* executable_name); + +// Set the arguments used by Platform.executableArguments. +void SetExecutableArguments(int script_index, char** argv); + +// Set dart:io implementation specific fields of Dart_EmbedderInformation. +void GetIOEmbedderInformation(Dart_EmbedderInformation* info); + +// Appropriate to assign to Dart_InitializeParams.file_open/read/write/close. +void* OpenFile(const char* name, bool write); +void ReadFile(uint8_t** data, intptr_t* file_len, void* stream); +void WriteFile(const void* buffer, intptr_t num_bytes, void* stream); +void CloseFile(void* stream); + +// Generates 'length' random bytes into 'buffer'. Returns true on success +// and false on failure. This is appropriate to assign to +// Dart_InitializeParams.entropy_source. +bool GetEntropy(uint8_t* buffer, intptr_t length); + +// Performs a lookup of the I/O Dart_NativeFunction with a specified 'name' and +// 'argument_count'. Returns NULL if no I/O native function with a matching +// name and parameter count is found. +Dart_NativeFunction LookupIONative(Dart_Handle name, + int argument_count, + bool* auto_setup_scope); + +// Returns the symbol for I/O native function 'nf'. Returns NULL if 'nf' is not +// a valid I/O native function. +const uint8_t* LookupIONativeSymbol(Dart_NativeFunction nf); + +} // namespace bin +} // namespace dart + +#endif // RUNTIME_INCLUDE_BIN_DART_IO_API_H_ diff --git a/pkgs/jni/src/include/dart_api.h b/pkgs/jni/src/include/dart_api.h new file mode 100644 index 000000000..99dde6f9d --- /dev/null +++ b/pkgs/jni/src/include/dart_api.h @@ -0,0 +1,4185 @@ +/* + * Copyright (c) 2012, 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. + */ + +#ifndef RUNTIME_INCLUDE_DART_API_H_ +#define RUNTIME_INCLUDE_DART_API_H_ + +/** \mainpage Dart Embedding API Reference + * + * This reference describes the Dart Embedding API, which is used to embed the + * Dart Virtual Machine within C/C++ applications. + * + * This reference is generated from the header include/dart_api.h. + */ + +/* __STDC_FORMAT_MACROS has to be defined before including to + * enable platform independent printf format specifiers. */ +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif + +#include +#include +#include + +#if defined(__Fuchsia__) +#include +#endif + +#ifdef __cplusplus +#define DART_EXTERN_C extern "C" +#else +#define DART_EXTERN_C extern +#endif + +#if defined(__CYGWIN__) +#error Tool chain and platform not supported. +#elif defined(_WIN32) +#if defined(DART_SHARED_LIB) +#define DART_EXPORT DART_EXTERN_C __declspec(dllexport) +#else +#define DART_EXPORT DART_EXTERN_C +#endif +#else +#if __GNUC__ >= 4 +#if defined(DART_SHARED_LIB) +#define DART_EXPORT \ + DART_EXTERN_C __attribute__((visibility("default"))) __attribute((used)) +#else +#define DART_EXPORT DART_EXTERN_C +#endif +#else +#error Tool chain not supported. +#endif +#endif + +#if __GNUC__ +#define DART_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#elif _MSC_VER +#define DART_WARN_UNUSED_RESULT _Check_return_ +#else +#define DART_WARN_UNUSED_RESULT +#endif + +/* + * ======= + * Handles + * ======= + */ + +/** + * An isolate is the unit of concurrency in Dart. Each isolate has + * its own memory and thread of control. No state is shared between + * isolates. Instead, isolates communicate by message passing. + * + * Each thread keeps track of its current isolate, which is the + * isolate which is ready to execute on the current thread. The + * current isolate may be NULL, in which case no isolate is ready to + * execute. Most of the Dart apis require there to be a current + * isolate in order to function without error. The current isolate is + * set by any call to Dart_CreateIsolateGroup or Dart_EnterIsolate. + */ +typedef struct _Dart_Isolate* Dart_Isolate; +typedef struct _Dart_IsolateGroup* Dart_IsolateGroup; + +/** + * An object reference managed by the Dart VM garbage collector. + * + * Because the garbage collector may move objects, it is unsafe to + * refer to objects directly. Instead, we refer to objects through + * handles, which are known to the garbage collector and updated + * automatically when the object is moved. Handles should be passed + * by value (except in cases like out-parameters) and should never be + * allocated on the heap. + * + * Most functions in the Dart Embedding API return a handle. When a + * function completes normally, this will be a valid handle to an + * object in the Dart VM heap. This handle may represent the result of + * the operation or it may be a special valid handle used merely to + * indicate successful completion. Note that a valid handle may in + * some cases refer to the null object. + * + * --- Error handles --- + * + * When a function encounters a problem that prevents it from + * completing normally, it returns an error handle (See Dart_IsError). + * An error handle has an associated error message that gives more + * details about the problem (See Dart_GetError). + * + * There are four kinds of error handles that can be produced, + * depending on what goes wrong: + * + * - Api error handles are produced when an api function is misused. + * This happens when a Dart embedding api function is called with + * invalid arguments or in an invalid context. + * + * - Unhandled exception error handles are produced when, during the + * execution of Dart code, an exception is thrown but not caught. + * Prototypically this would occur during a call to Dart_Invoke, but + * it can occur in any function which triggers the execution of Dart + * code (for example, Dart_ToString). + * + * An unhandled exception error provides access to an exception and + * stacktrace via the functions Dart_ErrorGetException and + * Dart_ErrorGetStackTrace. + * + * - Compilation error handles are produced when, during the execution + * of Dart code, a compile-time error occurs. As above, this can + * occur in any function which triggers the execution of Dart code. + * + * - Fatal error handles are produced when the system wants to shut + * down the current isolate. + * + * --- Propagating errors --- + * + * When an error handle is returned from the top level invocation of + * Dart code in a program, the embedder must handle the error as they + * see fit. Often, the embedder will print the error message produced + * by Dart_Error and exit the program. + * + * When an error is returned while in the body of a native function, + * it can be propagated up the call stack by calling + * Dart_PropagateError, Dart_SetReturnValue, or Dart_ThrowException. + * Errors should be propagated unless there is a specific reason not + * to. If an error is not propagated then it is ignored. For + * example, if an unhandled exception error is ignored, that + * effectively "catches" the unhandled exception. Fatal errors must + * always be propagated. + * + * When an error is propagated, any current scopes created by + * Dart_EnterScope will be exited. + * + * Using Dart_SetReturnValue to propagate an exception is somewhat + * more convenient than using Dart_PropagateError, and should be + * preferred for reasons discussed below. + * + * Dart_PropagateError and Dart_ThrowException do not return. Instead + * they transfer control non-locally using a setjmp-like mechanism. + * This can be inconvenient if you have resources that you need to + * clean up before propagating the error. + * + * When relying on Dart_PropagateError, we often return error handles + * rather than propagating them from helper functions. Consider the + * following contrived example: + * + * 1 Dart_Handle isLongStringHelper(Dart_Handle arg) { + * 2 intptr_t* length = 0; + * 3 result = Dart_StringLength(arg, &length); + * 4 if (Dart_IsError(result)) { + * 5 return result; + * 6 } + * 7 return Dart_NewBoolean(length > 100); + * 8 } + * 9 + * 10 void NativeFunction_isLongString(Dart_NativeArguments args) { + * 11 Dart_EnterScope(); + * 12 AllocateMyResource(); + * 13 Dart_Handle arg = Dart_GetNativeArgument(args, 0); + * 14 Dart_Handle result = isLongStringHelper(arg); + * 15 if (Dart_IsError(result)) { + * 16 FreeMyResource(); + * 17 Dart_PropagateError(result); + * 18 abort(); // will not reach here + * 19 } + * 20 Dart_SetReturnValue(result); + * 21 FreeMyResource(); + * 22 Dart_ExitScope(); + * 23 } + * + * In this example, we have a native function which calls a helper + * function to do its work. On line 5, the helper function could call + * Dart_PropagateError, but that would not give the native function a + * chance to call FreeMyResource(), causing a leak. Instead, the + * helper function returns the error handle to the caller, giving the + * caller a chance to clean up before propagating the error handle. + * + * When an error is propagated by calling Dart_SetReturnValue, the + * native function will be allowed to complete normally and then the + * exception will be propagated only once the native call + * returns. This can be convenient, as it allows the C code to clean + * up normally. + * + * The example can be written more simply using Dart_SetReturnValue to + * propagate the error. + * + * 1 Dart_Handle isLongStringHelper(Dart_Handle arg) { + * 2 intptr_t* length = 0; + * 3 result = Dart_StringLength(arg, &length); + * 4 if (Dart_IsError(result)) { + * 5 return result + * 6 } + * 7 return Dart_NewBoolean(length > 100); + * 8 } + * 9 + * 10 void NativeFunction_isLongString(Dart_NativeArguments args) { + * 11 Dart_EnterScope(); + * 12 AllocateMyResource(); + * 13 Dart_Handle arg = Dart_GetNativeArgument(args, 0); + * 14 Dart_SetReturnValue(isLongStringHelper(arg)); + * 15 FreeMyResource(); + * 16 Dart_ExitScope(); + * 17 } + * + * In this example, the call to Dart_SetReturnValue on line 14 will + * either return the normal return value or the error (potentially + * generated on line 3). The call to FreeMyResource on line 15 will + * execute in either case. + * + * --- Local and persistent handles --- + * + * Local handles are allocated within the current scope (see + * Dart_EnterScope) and go away when the current scope exits. Unless + * otherwise indicated, callers should assume that all functions in + * the Dart embedding api return local handles. + * + * Persistent handles are allocated within the current isolate. They + * can be used to store objects across scopes. Persistent handles have + * the lifetime of the current isolate unless they are explicitly + * deallocated (see Dart_DeletePersistentHandle). + * The type Dart_Handle represents a handle (both local and persistent). + * The type Dart_PersistentHandle is a Dart_Handle and it is used to + * document that a persistent handle is expected as a parameter to a call + * or the return value from a call is a persistent handle. + * + * FinalizableHandles are persistent handles which are auto deleted when + * the object is garbage collected. It is never safe to use these handles + * unless you know the object is still reachable. + * + * WeakPersistentHandles are persistent handles which are automatically set + * to point Dart_Null when the object is garbage collected. They are not auto + * deleted, so it is safe to use them after the object has become unreachable. + */ +typedef struct _Dart_Handle* Dart_Handle; +typedef Dart_Handle Dart_PersistentHandle; +typedef struct _Dart_WeakPersistentHandle* Dart_WeakPersistentHandle; +typedef struct _Dart_FinalizableHandle* Dart_FinalizableHandle; +// These structs are versioned by DART_API_DL_MAJOR_VERSION, bump the +// version when changing this struct. + +typedef void (*Dart_HandleFinalizer)(void* isolate_callback_data, void* peer); + +/** + * Is this an error handle? + * + * Requires there to be a current isolate. + */ +DART_EXPORT bool Dart_IsError(Dart_Handle handle); + +/** + * Is this an api error handle? + * + * Api error handles are produced when an api function is misused. + * This happens when a Dart embedding api function is called with + * invalid arguments or in an invalid context. + * + * Requires there to be a current isolate. + */ +DART_EXPORT bool Dart_IsApiError(Dart_Handle handle); + +/** + * Is this an unhandled exception error handle? + * + * Unhandled exception error handles are produced when, during the + * execution of Dart code, an exception is thrown but not caught. + * This can occur in any function which triggers the execution of Dart + * code. + * + * See Dart_ErrorGetException and Dart_ErrorGetStackTrace. + * + * Requires there to be a current isolate. + */ +DART_EXPORT bool Dart_IsUnhandledExceptionError(Dart_Handle handle); + +/** + * Is this a compilation error handle? + * + * Compilation error handles are produced when, during the execution + * of Dart code, a compile-time error occurs. This can occur in any + * function which triggers the execution of Dart code. + * + * Requires there to be a current isolate. + */ +DART_EXPORT bool Dart_IsCompilationError(Dart_Handle handle); + +/** + * Is this a fatal error handle? + * + * Fatal error handles are produced when the system wants to shut down + * the current isolate. + * + * Requires there to be a current isolate. + */ +DART_EXPORT bool Dart_IsFatalError(Dart_Handle handle); + +/** + * Gets the error message from an error handle. + * + * Requires there to be a current isolate. + * + * \return A C string containing an error message if the handle is + * error. An empty C string ("") if the handle is valid. This C + * String is scope allocated and is only valid until the next call + * to Dart_ExitScope. +*/ +DART_EXPORT const char* Dart_GetError(Dart_Handle handle); + +/** + * Is this an error handle for an unhandled exception? + */ +DART_EXPORT bool Dart_ErrorHasException(Dart_Handle handle); + +/** + * Gets the exception Object from an unhandled exception error handle. + */ +DART_EXPORT Dart_Handle Dart_ErrorGetException(Dart_Handle handle); + +/** + * Gets the stack trace Object from an unhandled exception error handle. + */ +DART_EXPORT Dart_Handle Dart_ErrorGetStackTrace(Dart_Handle handle); + +/** + * Produces an api error handle with the provided error message. + * + * Requires there to be a current isolate. + * + * \param error the error message. + */ +DART_EXPORT Dart_Handle Dart_NewApiError(const char* error); +DART_EXPORT Dart_Handle Dart_NewCompilationError(const char* error); + +/** + * Produces a new unhandled exception error handle. + * + * Requires there to be a current isolate. + * + * \param exception An instance of a Dart object to be thrown or + * an ApiError or CompilationError handle. + * When an ApiError or CompilationError handle is passed in + * a string object of the error message is created and it becomes + * the Dart object to be thrown. + */ +DART_EXPORT Dart_Handle Dart_NewUnhandledExceptionError(Dart_Handle exception); + +/** + * Propagates an error. + * + * If the provided handle is an unhandled exception error, this + * function will cause the unhandled exception to be rethrown. This + * will proceed in the standard way, walking up Dart frames until an + * appropriate 'catch' block is found, executing 'finally' blocks, + * etc. + * + * If the error is not an unhandled exception error, we will unwind + * the stack to the next C frame. Intervening Dart frames will be + * discarded; specifically, 'finally' blocks will not execute. This + * is the standard way that compilation errors (and the like) are + * handled by the Dart runtime. + * + * In either case, when an error is propagated any current scopes + * created by Dart_EnterScope will be exited. + * + * See the additional discussion under "Propagating Errors" at the + * beginning of this file. + * + * \param handle An error handle (See Dart_IsError) + * + * On success, this function does not return. On failure, the + * process is terminated. + */ +DART_EXPORT void Dart_PropagateError(Dart_Handle handle); + +/** + * Converts an object to a string. + * + * May generate an unhandled exception error. + * + * \return The converted string if no error occurs during + * the conversion. If an error does occur, an error handle is + * returned. + */ +DART_EXPORT Dart_Handle Dart_ToString(Dart_Handle object); + +/** + * Checks to see if two handles refer to identically equal objects. + * + * If both handles refer to instances, this is equivalent to using the top-level + * function identical() from dart:core. Otherwise, returns whether the two + * argument handles refer to the same object. + * + * \param obj1 An object to be compared. + * \param obj2 An object to be compared. + * + * \return True if the objects are identically equal. False otherwise. + */ +DART_EXPORT bool Dart_IdentityEquals(Dart_Handle obj1, Dart_Handle obj2); + +/** + * Allocates a handle in the current scope from a persistent handle. + */ +DART_EXPORT Dart_Handle Dart_HandleFromPersistent(Dart_PersistentHandle object); + +/** + * Allocates a handle in the current scope from a weak persistent handle. + * + * This will be a handle to Dart_Null if the object has been garbage collected. + */ +DART_EXPORT Dart_Handle +Dart_HandleFromWeakPersistent(Dart_WeakPersistentHandle object); + +/** + * Allocates a persistent handle for an object. + * + * This handle has the lifetime of the current isolate unless it is + * explicitly deallocated by calling Dart_DeletePersistentHandle. + * + * Requires there to be a current isolate. + */ +DART_EXPORT Dart_PersistentHandle Dart_NewPersistentHandle(Dart_Handle object); + +/** + * Assign value of local handle to a persistent handle. + * + * Requires there to be a current isolate. + * + * \param obj1 A persistent handle whose value needs to be set. + * \param obj2 An object whose value needs to be set to the persistent handle. + */ +DART_EXPORT void Dart_SetPersistentHandle(Dart_PersistentHandle obj1, + Dart_Handle obj2); + +/** + * Deallocates a persistent handle. + * + * Requires there to be a current isolate group. + */ +DART_EXPORT void Dart_DeletePersistentHandle(Dart_PersistentHandle object); + +/** + * Allocates a weak persistent handle for an object. + * + * This handle has the lifetime of the current isolate. The handle can also be + * explicitly deallocated by calling Dart_DeleteWeakPersistentHandle. + * + * If the object becomes unreachable the callback is invoked with the peer as + * argument. The callback can be executed on any thread, will have a current + * isolate group, but will not have a current isolate. The callback can only + * call Dart_DeletePersistentHandle or Dart_DeleteWeakPersistentHandle. This + * gives the embedder the ability to cleanup data associated with the object. + * The handle will point to the Dart_Null object after the finalizer has been + * run. It is illegal to call into the VM with any other Dart_* functions from + * the callback. If the handle is deleted before the object becomes + * unreachable, the callback is never invoked. + * + * Requires there to be a current isolate. + * + * \param object An object with identity. + * \param peer A pointer to a native object or NULL. This value is + * provided to callback when it is invoked. + * \param external_allocation_size The number of externally allocated + * bytes for peer. Used to inform the garbage collector. + * \param callback A function pointer that will be invoked sometime + * after the object is garbage collected, unless the handle has been deleted. + * A valid callback needs to be specified it cannot be NULL. + * + * \return The weak persistent handle or NULL. NULL is returned in case of bad + * parameters. + */ +DART_EXPORT Dart_WeakPersistentHandle +Dart_NewWeakPersistentHandle(Dart_Handle object, + void* peer, + intptr_t external_allocation_size, + Dart_HandleFinalizer callback); + +/** + * Deletes the given weak persistent [object] handle. + * + * Requires there to be a current isolate group. + */ +DART_EXPORT void Dart_DeleteWeakPersistentHandle( + Dart_WeakPersistentHandle object); + +/** + * Updates the external memory size for the given weak persistent handle. + * + * May trigger garbage collection. + */ +DART_EXPORT void Dart_UpdateExternalSize(Dart_WeakPersistentHandle object, + intptr_t external_allocation_size); + +/** + * Allocates a finalizable handle for an object. + * + * This handle has the lifetime of the current isolate group unless the object + * pointed to by the handle is garbage collected, in this case the VM + * automatically deletes the handle after invoking the callback associated + * with the handle. The handle can also be explicitly deallocated by + * calling Dart_DeleteFinalizableHandle. + * + * If the object becomes unreachable the callback is invoked with the + * the peer as argument. The callback can be executed on any thread, will have + * an isolate group, but will not have a current isolate. The callback can only + * call Dart_DeletePersistentHandle or Dart_DeleteWeakPersistentHandle. + * This gives the embedder the ability to cleanup data associated with the + * object and clear out any cached references to the handle. All references to + * this handle after the callback will be invalid. It is illegal to call into + * the VM with any other Dart_* functions from the callback. If the handle is + * deleted before the object becomes unreachable, the callback is never + * invoked. + * + * Requires there to be a current isolate. + * + * \param object An object with identity. + * \param peer A pointer to a native object or NULL. This value is + * provided to callback when it is invoked. + * \param external_allocation_size The number of externally allocated + * bytes for peer. Used to inform the garbage collector. + * \param callback A function pointer that will be invoked sometime + * after the object is garbage collected, unless the handle has been deleted. + * A valid callback needs to be specified it cannot be NULL. + * + * \return The finalizable handle or NULL. NULL is returned in case of bad + * parameters. + */ +DART_EXPORT Dart_FinalizableHandle +Dart_NewFinalizableHandle(Dart_Handle object, + void* peer, + intptr_t external_allocation_size, + Dart_HandleFinalizer callback); + +/** + * Deletes the given finalizable [object] handle. + * + * The caller has to provide the actual Dart object the handle was created from + * to prove the object (and therefore the finalizable handle) is still alive. + * + * Requires there to be a current isolate. + */ +DART_EXPORT void Dart_DeleteFinalizableHandle(Dart_FinalizableHandle object, + Dart_Handle strong_ref_to_object); + +/** + * Updates the external memory size for the given finalizable handle. + * + * The caller has to provide the actual Dart object the handle was created from + * to prove the object (and therefore the finalizable handle) is still alive. + * + * May trigger garbage collection. + */ +DART_EXPORT void Dart_UpdateFinalizableExternalSize( + Dart_FinalizableHandle object, + Dart_Handle strong_ref_to_object, + intptr_t external_allocation_size); + +/* + * ========================== + * Initialization and Globals + * ========================== + */ + +/** + * Gets the version string for the Dart VM. + * + * The version of the Dart VM can be accessed without initializing the VM. + * + * \return The version string for the embedded Dart VM. + */ +DART_EXPORT const char* Dart_VersionString(void); + +/** + * Isolate specific flags are set when creating a new isolate using the + * Dart_IsolateFlags structure. + * + * Current version of flags is encoded in a 32-bit integer with 16 bits used + * for each part. + */ + +#define DART_FLAGS_CURRENT_VERSION (0x0000000c) + +typedef struct { + int32_t version; + bool enable_asserts; + bool use_field_guards; + bool use_osr; + bool obfuscate; + bool load_vmservice_library; + bool copy_parent_code; + bool null_safety; + bool is_system_isolate; + bool snapshot_is_dontneed_safe; + bool branch_coverage; +} Dart_IsolateFlags; + +/** + * Initialize Dart_IsolateFlags with correct version and default values. + */ +DART_EXPORT void Dart_IsolateFlagsInitialize(Dart_IsolateFlags* flags); + +/** + * An isolate creation and initialization callback function. + * + * This callback, provided by the embedder, is called when the VM + * needs to create an isolate. The callback should create an isolate + * by calling Dart_CreateIsolateGroup and load any scripts required for + * execution. + * + * This callback may be called on a different thread than the one + * running the parent isolate. + * + * When the function returns NULL, it is the responsibility of this + * function to ensure that Dart_ShutdownIsolate has been called if + * required (for example, if the isolate was created successfully by + * Dart_CreateIsolateGroup() but the root library fails to load + * successfully, then the function should call Dart_ShutdownIsolate + * before returning). + * + * When the function returns NULL, the function should set *error to + * a malloc-allocated buffer containing a useful error message. The + * caller of this function (the VM) will make sure that the buffer is + * freed. + * + * \param script_uri The uri of the main source file or snapshot to load. + * Either the URI of the parent isolate set in Dart_CreateIsolateGroup for + * Isolate.spawn, or the argument to Isolate.spawnUri canonicalized by the + * library tag handler of the parent isolate. + * The callback is responsible for loading the program by a call to + * Dart_LoadScriptFromKernel. + * \param main The name of the main entry point this isolate will + * eventually run. This is provided for advisory purposes only to + * improve debugging messages. The main function is not invoked by + * this function. + * \param package_root Ignored. + * \param package_config Uri of the package configuration file (either in format + * of .packages or .dart_tool/package_config.json) for this isolate + * to resolve package imports against. If this parameter is not passed the + * package resolution of the parent isolate should be used. + * \param flags Default flags for this isolate being spawned. Either inherited + * from the spawning isolate or passed as parameters when spawning the + * isolate from Dart code. + * \param isolate_data The isolate data which was passed to the + * parent isolate when it was created by calling Dart_CreateIsolateGroup(). + * \param error A structure into which the embedder can place a + * C string containing an error message in the case of failures. + * + * \return The embedder returns NULL if the creation and + * initialization was not successful and the isolate if successful. + */ +typedef Dart_Isolate (*Dart_IsolateGroupCreateCallback)( + const char* script_uri, + const char* main, + const char* package_root, + const char* package_config, + Dart_IsolateFlags* flags, + void* isolate_data, + char** error); + +/** + * An isolate initialization callback function. + * + * This callback, provided by the embedder, is called when the VM has created an + * isolate within an existing isolate group (i.e. from the same source as an + * existing isolate). + * + * The callback should setup native resolvers and might want to set a custom + * message handler via [Dart_SetMessageNotifyCallback] and mark the isolate as + * runnable. + * + * This callback may be called on a different thread than the one + * running the parent isolate. + * + * When the function returns `false`, it is the responsibility of this + * function to ensure that `Dart_ShutdownIsolate` has been called. + * + * When the function returns `false`, the function should set *error to + * a malloc-allocated buffer containing a useful error message. The + * caller of this function (the VM) will make sure that the buffer is + * freed. + * + * \param child_isolate_data The callback data to associate with the new + * child isolate. + * \param error A structure into which the embedder can place a + * C string containing an error message in the case the initialization fails. + * + * \return The embedder returns true if the initialization was successful and + * false otherwise (in which case the VM will terminate the isolate). + */ +typedef bool (*Dart_InitializeIsolateCallback)(void** child_isolate_data, + char** error); + +/** + * An isolate shutdown callback function. + * + * This callback, provided by the embedder, is called before the vm + * shuts down an isolate. The isolate being shutdown will be the current + * isolate. It is safe to run Dart code. + * + * This function should be used to dispose of native resources that + * are allocated to an isolate in order to avoid leaks. + * + * \param isolate_group_data The same callback data which was passed to the + * isolate group when it was created. + * \param isolate_data The same callback data which was passed to the isolate + * when it was created. + */ +typedef void (*Dart_IsolateShutdownCallback)(void* isolate_group_data, + void* isolate_data); + +/** + * An isolate cleanup callback function. + * + * This callback, provided by the embedder, is called after the vm + * shuts down an isolate. There will be no current isolate and it is *not* + * safe to run Dart code. + * + * This function should be used to dispose of native resources that + * are allocated to an isolate in order to avoid leaks. + * + * \param isolate_group_data The same callback data which was passed to the + * isolate group when it was created. + * \param isolate_data The same callback data which was passed to the isolate + * when it was created. + */ +typedef void (*Dart_IsolateCleanupCallback)(void* isolate_group_data, + void* isolate_data); + +/** + * An isolate group cleanup callback function. + * + * This callback, provided by the embedder, is called after the vm + * shuts down an isolate group. + * + * This function should be used to dispose of native resources that + * are allocated to an isolate in order to avoid leaks. + * + * \param isolate_group_data The same callback data which was passed to the + * isolate group when it was created. + * + */ +typedef void (*Dart_IsolateGroupCleanupCallback)(void* isolate_group_data); + +/** + * A thread start callback function. + * This callback, provided by the embedder, is called after a thread in the + * vm thread pool starts. + * This function could be used to adjust thread priority or attach native + * resources to the thread. + */ +typedef void (*Dart_ThreadStartCallback)(void); + +/** + * A thread death callback function. + * This callback, provided by the embedder, is called before a thread in the + * vm thread pool exits. + * This function could be used to dispose of native resources that + * are associated and attached to the thread, in order to avoid leaks. + */ +typedef void (*Dart_ThreadExitCallback)(void); + +/** + * Opens a file for reading or writing. + * + * Callback provided by the embedder for file operations. If the + * embedder does not allow file operations this callback can be + * NULL. + * + * \param name The name of the file to open. + * \param write A boolean variable which indicates if the file is to + * opened for writing. If there is an existing file it needs to truncated. + */ +typedef void* (*Dart_FileOpenCallback)(const char* name, bool write); + +/** + * Read contents of file. + * + * Callback provided by the embedder for file operations. If the + * embedder does not allow file operations this callback can be + * NULL. + * + * \param data Buffer allocated in the callback into which the contents + * of the file are read into. It is the responsibility of the caller to + * free this buffer. + * \param file_length A variable into which the length of the file is returned. + * In the case of an error this value would be -1. + * \param stream Handle to the opened file. + */ +typedef void (*Dart_FileReadCallback)(uint8_t** data, + intptr_t* file_length, + void* stream); + +/** + * Write data into file. + * + * Callback provided by the embedder for file operations. If the + * embedder does not allow file operations this callback can be + * NULL. + * + * \param data Buffer which needs to be written into the file. + * \param length Length of the buffer. + * \param stream Handle to the opened file. + */ +typedef void (*Dart_FileWriteCallback)(const void* data, + intptr_t length, + void* stream); + +/** + * Closes the opened file. + * + * Callback provided by the embedder for file operations. If the + * embedder does not allow file operations this callback can be + * NULL. + * + * \param stream Handle to the opened file. + */ +typedef void (*Dart_FileCloseCallback)(void* stream); + +typedef bool (*Dart_EntropySource)(uint8_t* buffer, intptr_t length); + +/** + * Callback provided by the embedder that is used by the vmservice isolate + * to request the asset archive. The asset archive must be an uncompressed tar + * archive that is stored in a Uint8List. + * + * If the embedder has no vmservice isolate assets, the callback can be NULL. + * + * \return The embedder must return a handle to a Uint8List containing an + * uncompressed tar archive or null. + */ +typedef Dart_Handle (*Dart_GetVMServiceAssetsArchive)(void); + +/** + * The current version of the Dart_InitializeFlags. Should be incremented every + * time Dart_InitializeFlags changes in a binary incompatible way. + */ +#define DART_INITIALIZE_PARAMS_CURRENT_VERSION (0x00000008) + +/** Forward declaration */ +struct Dart_CodeObserver; + +/** + * Callback provided by the embedder that is used by the VM to notify on code + * object creation, *before* it is invoked the first time. + * This is useful for embedders wanting to e.g. keep track of PCs beyond + * the lifetime of the garbage collected code objects. + * Note that an address range may be used by more than one code object over the + * lifecycle of a process. Clients of this function should record timestamps for + * these compilation events and when collecting PCs to disambiguate reused + * address ranges. + */ +typedef void (*Dart_OnNewCodeCallback)(struct Dart_CodeObserver* observer, + const char* name, + uintptr_t base, + uintptr_t size); + +typedef struct Dart_CodeObserver { + void* data; + + Dart_OnNewCodeCallback on_new_code; +} Dart_CodeObserver; + +/** + * Optional callback provided by the embedder that is used by the VM to + * implement registration of kernel blobs for the subsequent Isolate.spawnUri + * If no callback is provided, the registration of kernel blobs will throw + * an error. + * + * \param kernel_buffer A buffer which contains a kernel program. Callback + * should copy the contents of `kernel_buffer` as + * it may be freed immediately after registration. + * \param kernel_buffer_size The size of `kernel_buffer`. + * + * \return A C string representing URI which can be later used + * to spawn a new isolate. This C String should be scope allocated + * or owned by the embedder. + * Returns NULL if embedder runs out of memory. + */ +typedef const char* (*Dart_RegisterKernelBlobCallback)( + const uint8_t* kernel_buffer, + intptr_t kernel_buffer_size); + +/** + * Optional callback provided by the embedder that is used by the VM to + * unregister kernel blobs. + * If no callback is provided, the unregistration of kernel blobs will throw + * an error. + * + * \param kernel_blob_uri URI of the kernel blob to unregister. + */ +typedef void (*Dart_UnregisterKernelBlobCallback)(const char* kernel_blob_uri); + +/** + * Describes how to initialize the VM. Used with Dart_Initialize. + */ +typedef struct { + /** + * Identifies the version of the struct used by the client. + * should be initialized to DART_INITIALIZE_PARAMS_CURRENT_VERSION. + */ + int32_t version; + + /** + * A buffer containing snapshot data, or NULL if no snapshot is provided. + * + * If provided, the buffer must remain valid until Dart_Cleanup returns. + */ + const uint8_t* vm_snapshot_data; + + /** + * A buffer containing a snapshot of precompiled instructions, or NULL if + * no snapshot is provided. + * + * If provided, the buffer must remain valid until Dart_Cleanup returns. + */ + const uint8_t* vm_snapshot_instructions; + + /** + * A function to be called during isolate group creation. + * See Dart_IsolateGroupCreateCallback. + */ + Dart_IsolateGroupCreateCallback create_group; + + /** + * A function to be called during isolate + * initialization inside an existing isolate group. + * See Dart_InitializeIsolateCallback. + */ + Dart_InitializeIsolateCallback initialize_isolate; + + /** + * A function to be called right before an isolate is shutdown. + * See Dart_IsolateShutdownCallback. + */ + Dart_IsolateShutdownCallback shutdown_isolate; + + /** + * A function to be called after an isolate was shutdown. + * See Dart_IsolateCleanupCallback. + */ + Dart_IsolateCleanupCallback cleanup_isolate; + + /** + * A function to be called after an isolate group is + * shutdown. See Dart_IsolateGroupCleanupCallback. + */ + Dart_IsolateGroupCleanupCallback cleanup_group; + + Dart_ThreadStartCallback thread_start; + Dart_ThreadExitCallback thread_exit; + Dart_FileOpenCallback file_open; + Dart_FileReadCallback file_read; + Dart_FileWriteCallback file_write; + Dart_FileCloseCallback file_close; + Dart_EntropySource entropy_source; + + /** + * A function to be called by the service isolate when it requires the + * vmservice assets archive. See Dart_GetVMServiceAssetsArchive. + */ + Dart_GetVMServiceAssetsArchive get_service_assets; + + bool start_kernel_isolate; + + /** + * An external code observer callback function. The observer can be invoked + * as early as during the Dart_Initialize() call. + */ + Dart_CodeObserver* code_observer; + + /** + * Kernel blob registration callback function. See Dart_RegisterKernelBlobCallback. + */ + Dart_RegisterKernelBlobCallback register_kernel_blob; + + /** + * Kernel blob unregistration callback function. See Dart_UnregisterKernelBlobCallback. + */ + Dart_UnregisterKernelBlobCallback unregister_kernel_blob; + +#if defined(__Fuchsia__) + /** + * The resource needed to use zx_vmo_replace_as_executable. Can be + * ZX_HANDLE_INVALID if the process has ambient-replace-as-executable or if + * executable memory is not needed (e.g., this is an AOT runtime). + */ + zx_handle_t vmex_resource; +#endif +} Dart_InitializeParams; + +/** + * Initializes the VM. + * + * \param params A struct containing initialization information. The version + * field of the struct must be DART_INITIALIZE_PARAMS_CURRENT_VERSION. + * + * \return NULL if initialization is successful. Returns an error message + * otherwise. The caller is responsible for freeing the error message. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT char* Dart_Initialize( + Dart_InitializeParams* params); + +/** + * Cleanup state in the VM before process termination. + * + * \return NULL if cleanup is successful. Returns an error message otherwise. + * The caller is responsible for freeing the error message. + * + * NOTE: This function must not be called on a thread that was created by the VM + * itself. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT char* Dart_Cleanup(void); + +/** + * Sets command line flags. Should be called before Dart_Initialize. + * + * \param argc The length of the arguments array. + * \param argv An array of arguments. + * + * \return NULL if successful. Returns an error message otherwise. + * The caller is responsible for freeing the error message. + * + * NOTE: This call does not store references to the passed in c-strings. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT char* Dart_SetVMFlags(int argc, + const char** argv); + +/** + * Returns true if the named VM flag is of boolean type, specified, and set to + * true. + * + * \param flag_name The name of the flag without leading punctuation + * (example: "enable_asserts"). + */ +DART_EXPORT bool Dart_IsVMFlagSet(const char* flag_name); + +/* + * ======== + * Isolates + * ======== + */ + +/** + * Creates a new isolate. The new isolate becomes the current isolate. + * + * A snapshot can be used to restore the VM quickly to a saved state + * and is useful for fast startup. If snapshot data is provided, the + * isolate will be started using that snapshot data. Requires a core snapshot or + * an app snapshot created by Dart_CreateSnapshot or + * Dart_CreatePrecompiledSnapshot* from a VM with the same version. + * + * Requires there to be no current isolate. + * + * \param script_uri The main source file or snapshot this isolate will load. + * The VM will provide this URI to the Dart_IsolateGroupCreateCallback when a + * child isolate is created by Isolate.spawn. The embedder should use a URI + * that allows it to load the same program into such a child isolate. + * \param name A short name for the isolate to improve debugging messages. + * Typically of the format 'foo.dart:main()'. + * \param isolate_snapshot_data Buffer containing the snapshot data of the + * isolate or NULL if no snapshot is provided. If provided, the buffer must + * remain valid until the isolate shuts down. + * \param isolate_snapshot_instructions Buffer containing the snapshot + * instructions of the isolate or NULL if no snapshot is provided. If + * provided, the buffer must remain valid until the isolate shuts down. + * \param flags Pointer to VM specific flags or NULL for default flags. + * \param isolate_group_data Embedder group data. This data can be obtained + * by calling Dart_IsolateGroupData and will be passed to the + * Dart_IsolateShutdownCallback, Dart_IsolateCleanupCallback, and + * Dart_IsolateGroupCleanupCallback. + * \param isolate_data Embedder data. This data will be passed to + * the Dart_IsolateGroupCreateCallback when new isolates are spawned from + * this parent isolate. + * \param error Returns NULL if creation is successful, an error message + * otherwise. The caller is responsible for calling free() on the error + * message. + * + * \return The new isolate on success, or NULL if isolate creation failed. + */ +DART_EXPORT Dart_Isolate +Dart_CreateIsolateGroup(const char* script_uri, + const char* name, + const uint8_t* isolate_snapshot_data, + const uint8_t* isolate_snapshot_instructions, + Dart_IsolateFlags* flags, + void* isolate_group_data, + void* isolate_data, + char** error); +/** + * Creates a new isolate inside the isolate group of [group_member]. + * + * Requires there to be no current isolate. + * + * \param group_member An isolate from the same group into which the newly created + * isolate should be born into. Other threads may not have entered / enter this + * member isolate. + * \param name A short name for the isolate for debugging purposes. + * \param shutdown_callback A callback to be called when the isolate is being + * shutdown (may be NULL). + * \param cleanup_callback A callback to be called when the isolate is being + * cleaned up (may be NULL). + * \param child_isolate_data The embedder-specific data associated with this isolate. + * \param error Set to NULL if creation is successful, set to an error + * message otherwise. The caller is responsible for calling free() on the + * error message. + * + * \return The newly created isolate on success, or NULL if isolate creation + * failed. + * + * If successful, the newly created isolate will become the current isolate. + */ +DART_EXPORT Dart_Isolate +Dart_CreateIsolateInGroup(Dart_Isolate group_member, + const char* name, + Dart_IsolateShutdownCallback shutdown_callback, + Dart_IsolateCleanupCallback cleanup_callback, + void* child_isolate_data, + char** error); + +/* TODO(turnidge): Document behavior when there is already a current + * isolate. */ + +/** + * Creates a new isolate from a Dart Kernel file. The new isolate + * becomes the current isolate. + * + * Requires there to be no current isolate. + * + * \param script_uri The main source file or snapshot this isolate will load. + * The VM will provide this URI to the Dart_IsolateGroupCreateCallback when a + * child isolate is created by Isolate.spawn. The embedder should use a URI that + * allows it to load the same program into such a child isolate. + * \param name A short name for the isolate to improve debugging messages. + * Typically of the format 'foo.dart:main()'. + * \param kernel_buffer A buffer which contains a kernel/DIL program. Must + * remain valid until isolate shutdown. + * \param kernel_buffer_size The size of `kernel_buffer`. + * \param flags Pointer to VM specific flags or NULL for default flags. + * \param isolate_group_data Embedder group data. This data can be obtained + * by calling Dart_IsolateGroupData and will be passed to the + * Dart_IsolateShutdownCallback, Dart_IsolateCleanupCallback, and + * Dart_IsolateGroupCleanupCallback. + * \param isolate_data Embedder data. This data will be passed to + * the Dart_IsolateGroupCreateCallback when new isolates are spawned from + * this parent isolate. + * \param error Returns NULL if creation is successful, an error message + * otherwise. The caller is responsible for calling free() on the error + * message. + * + * \return The new isolate on success, or NULL if isolate creation failed. + */ +DART_EXPORT Dart_Isolate +Dart_CreateIsolateGroupFromKernel(const char* script_uri, + const char* name, + const uint8_t* kernel_buffer, + intptr_t kernel_buffer_size, + Dart_IsolateFlags* flags, + void* isolate_group_data, + void* isolate_data, + char** error); +/** + * Shuts down the current isolate. After this call, the current isolate is NULL. + * Any current scopes created by Dart_EnterScope will be exited. Invokes the + * shutdown callback and any callbacks of remaining weak persistent handles. + * + * Requires there to be a current isolate. + */ +DART_EXPORT void Dart_ShutdownIsolate(void); +/* TODO(turnidge): Document behavior when there is no current isolate. */ + +/** + * Returns the current isolate. Will return NULL if there is no + * current isolate. + */ +DART_EXPORT Dart_Isolate Dart_CurrentIsolate(void); + +/** + * Returns the callback data associated with the current isolate. This + * data was set when the isolate got created or initialized. + */ +DART_EXPORT void* Dart_CurrentIsolateData(void); + +/** + * Returns the callback data associated with the given isolate. This + * data was set when the isolate got created or initialized. + */ +DART_EXPORT void* Dart_IsolateData(Dart_Isolate isolate); + +/** + * Returns the current isolate group. Will return NULL if there is no + * current isolate group. + */ +DART_EXPORT Dart_IsolateGroup Dart_CurrentIsolateGroup(void); + +/** + * Returns the callback data associated with the current isolate group. This + * data was passed to the isolate group when it was created. + */ +DART_EXPORT void* Dart_CurrentIsolateGroupData(void); + +/** + * Gets an id that uniquely identifies current isolate group. + * + * It is the responsibility of the caller to free the returned ID. + */ +typedef int64_t Dart_IsolateGroupId; +DART_EXPORT Dart_IsolateGroupId Dart_CurrentIsolateGroupId(void); + +/** + * Returns the callback data associated with the specified isolate group. This + * data was passed to the isolate when it was created. + * The embedder is responsible for ensuring the consistency of this data + * with respect to the lifecycle of an isolate group. + */ +DART_EXPORT void* Dart_IsolateGroupData(Dart_Isolate isolate); + +/** + * Returns the debugging name for the current isolate. + * + * This name is unique to each isolate and should only be used to make + * debugging messages more comprehensible. + */ +DART_EXPORT Dart_Handle Dart_DebugName(void); + +/** + * Returns the debugging name for the current isolate. + * + * This name is unique to each isolate and should only be used to make + * debugging messages more comprehensible. + * + * The returned string is scope allocated and is only valid until the next call + * to Dart_ExitScope. + */ +DART_EXPORT const char* Dart_DebugNameToCString(void); + +/** + * Returns the ID for an isolate which is used to query the service protocol. + * + * It is the responsibility of the caller to free the returned ID. + */ +DART_EXPORT const char* Dart_IsolateServiceId(Dart_Isolate isolate); + +/** + * Enters an isolate. After calling this function, + * the current isolate will be set to the provided isolate. + * + * Requires there to be no current isolate. Multiple threads may not be in + * the same isolate at once. + */ +DART_EXPORT void Dart_EnterIsolate(Dart_Isolate isolate); + +/** + * Kills the given isolate. + * + * This function has the same effect as dart:isolate's + * Isolate.kill(priority:immediate). + * It can interrupt ordinary Dart code but not native code. If the isolate is + * in the middle of a long running native function, the isolate will not be + * killed until control returns to Dart. + * + * Does not require a current isolate. It is safe to kill the current isolate if + * there is one. + */ +DART_EXPORT void Dart_KillIsolate(Dart_Isolate isolate); + +/** + * Notifies the VM that the embedder expects to be idle until |deadline|. The VM + * may use this time to perform garbage collection or other tasks to avoid + * delays during execution of Dart code in the future. + * + * |deadline| is measured in microseconds against the system's monotonic time. + * This clock can be accessed via Dart_TimelineGetMicros(). + * + * Requires there to be a current isolate. + */ +DART_EXPORT void Dart_NotifyIdle(int64_t deadline); + +typedef void (*Dart_HeapSamplingReportCallback)(void* context, + void* data); + +typedef void* (*Dart_HeapSamplingCreateCallback)( + Dart_Isolate isolate, + Dart_IsolateGroup isolate_group, + const char* cls_name, + intptr_t allocation_size); +typedef void (*Dart_HeapSamplingDeleteCallback)(void* data); + +/** + * Starts the heap sampling profiler for each thread in the VM. + */ +DART_EXPORT void Dart_EnableHeapSampling(void); + +/* + * Stops the heap sampling profiler for each thread in the VM. + */ +DART_EXPORT void Dart_DisableHeapSampling(void); + +/* Registers callbacks are invoked once per sampled allocation upon object + * allocation and garbage collection. + * + * |create_callback| can be used to associate additional data with the sampled + * allocation, such as a stack trace. This data pointer will be passed to + * |delete_callback| to allow for proper disposal when the object associated + * with the allocation sample is collected. + * + * The provided callbacks must not call into the VM and should do as little + * work as possible to avoid performance penalities during object allocation and + * garbage collection. + * + * NOTE: It is a fatal error to set either callback to null once they have been + * initialized. + */ +DART_EXPORT void Dart_RegisterHeapSamplingCallback( + Dart_HeapSamplingCreateCallback create_callback, + Dart_HeapSamplingDeleteCallback delete_callback); + +/* + * Reports the surviving allocation samples for all live isolate groups in the + * VM. + * + * When the callback is invoked: + * - |context| will be the context object provided when invoking + * |Dart_ReportSurvivingAllocations|. This can be safely set to null if not + * required. + * - |heap_size| will be equal to the size of the allocated object associated + * with the sample. + * - |cls_name| will be a C String representing + * the class name of the allocated object. This string is valid for the + * duration of the call to Dart_ReportSurvivingAllocations and can be + * freed by the VM at any point after the method returns. + * - |data| will be set to the data associated with the sample by + * |Dart_HeapSamplingCreateCallback|. + * + * If |force_gc| is true, a full GC will be performed before reporting the + * allocations. + */ +DART_EXPORT void Dart_ReportSurvivingAllocations( + Dart_HeapSamplingReportCallback callback, + void* context, + bool force_gc); + +/* + * Sets the average heap sampling rate based on a number of |bytes| for each + * thread. + * + * In other words, approximately every |bytes| allocated will create a sample. + * Defaults to 512 KiB. + */ +DART_EXPORT void Dart_SetHeapSamplingPeriod(intptr_t bytes); + +/** + * Notifies the VM that the embedder expects the application's working set has + * recently shrunk significantly and is not expected to rise in the near future. + * The VM may spend O(heap-size) time performing clean up work. + * + * Requires there to be a current isolate. + */ +DART_EXPORT void Dart_NotifyDestroyed(void); + +/** + * Notifies the VM that the system is running low on memory. + * + * Does not require a current isolate. Only valid after calling Dart_Initialize. + */ +DART_EXPORT void Dart_NotifyLowMemory(void); + +typedef enum { + /** + * Balanced + */ + Dart_PerformanceMode_Default, + /** + * Optimize for low latency, at the expense of throughput and memory overhead + * by performing work in smaller batches (requiring more overhead) or by + * delaying work (requiring more memory). An embedder should not remain in + * this mode indefinitely. + */ + Dart_PerformanceMode_Latency, + /** + * Optimize for high throughput, at the expense of latency and memory overhead + * by performing work in larger batches with more intervening growth. + */ + Dart_PerformanceMode_Throughput, + /** + * Optimize for low memory, at the expensive of throughput and latency by more + * frequently performing work. + */ + Dart_PerformanceMode_Memory, +} Dart_PerformanceMode; + +/** + * Set the desired performance trade-off. + * + * Requires a current isolate. + * + * Returns the previous performance mode. + */ +DART_EXPORT Dart_PerformanceMode +Dart_SetPerformanceMode(Dart_PerformanceMode mode); + +/** + * Starts the CPU sampling profiler. + */ +DART_EXPORT void Dart_StartProfiling(void); + +/** + * Stops the CPU sampling profiler. + * + * Note that some profile samples might still be taken after this function + * returns due to the asynchronous nature of the implementation on some + * platforms. + */ +DART_EXPORT void Dart_StopProfiling(void); + +/** + * Notifies the VM that the current thread should not be profiled until a + * matching call to Dart_ThreadEnableProfiling is made. + * + * NOTE: By default, if a thread has entered an isolate it will be profiled. + * This function should be used when an embedder knows a thread is about + * to make a blocking call and wants to avoid unnecessary interrupts by + * the profiler. + */ +DART_EXPORT void Dart_ThreadDisableProfiling(void); + +/** + * Notifies the VM that the current thread should be profiled. + * + * NOTE: It is only legal to call this function *after* calling + * Dart_ThreadDisableProfiling. + * + * NOTE: By default, if a thread has entered an isolate it will be profiled. + */ +DART_EXPORT void Dart_ThreadEnableProfiling(void); + +/** + * Register symbol information for the Dart VM's profiler and crash dumps. + * + * This consumes the output of //topaz/runtime/dart/profiler_symbols, which + * should be treated as opaque. + */ +DART_EXPORT void Dart_AddSymbols(const char* dso_name, + void* buffer, + intptr_t buffer_size); + +/** + * Exits an isolate. After this call, Dart_CurrentIsolate will + * return NULL. + * + * Requires there to be a current isolate. + */ +DART_EXPORT void Dart_ExitIsolate(void); +/* TODO(turnidge): We don't want users of the api to be able to exit a + * "pure" dart isolate. Implement and document. */ + +/** + * Creates a full snapshot of the current isolate heap. + * + * A full snapshot is a compact representation of the dart vm isolate heap + * and dart isolate heap states. These snapshots are used to initialize + * the vm isolate on startup and fast initialization of an isolate. + * A Snapshot of the heap is created before any dart code has executed. + * + * Requires there to be a current isolate. Not available in the precompiled + * runtime (check Dart_IsPrecompiledRuntime). + * + * \param vm_snapshot_data_buffer Returns a pointer to a buffer containing the + * vm snapshot. This buffer is scope allocated and is only valid + * until the next call to Dart_ExitScope. + * \param vm_snapshot_data_size Returns the size of vm_snapshot_data_buffer. + * \param isolate_snapshot_data_buffer Returns a pointer to a buffer containing + * the isolate snapshot. This buffer is scope allocated and is only valid + * until the next call to Dart_ExitScope. + * \param isolate_snapshot_data_size Returns the size of + * isolate_snapshot_data_buffer. + * \param is_core Create a snapshot containing core libraries. + * Such snapshot should be agnostic to null safety mode. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle +Dart_CreateSnapshot(uint8_t** vm_snapshot_data_buffer, + intptr_t* vm_snapshot_data_size, + uint8_t** isolate_snapshot_data_buffer, + intptr_t* isolate_snapshot_data_size, + bool is_core); + +/** + * Returns whether the buffer contains a kernel file. + * + * \param buffer Pointer to a buffer that might contain a kernel binary. + * \param buffer_size Size of the buffer. + * + * \return Whether the buffer contains a kernel binary (full or partial). + */ +DART_EXPORT bool Dart_IsKernel(const uint8_t* buffer, intptr_t buffer_size); + +/** + * Make isolate runnable. + * + * When isolates are spawned, this function is used to indicate that + * the creation and initialization (including script loading) of the + * isolate is complete and the isolate can start. + * This function expects there to be no current isolate. + * + * \param isolate The isolate to be made runnable. + * + * \return NULL if successful. Returns an error message otherwise. The caller + * is responsible for freeing the error message. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT char* Dart_IsolateMakeRunnable( + Dart_Isolate isolate); + +/* + * ================== + * Messages and Ports + * ================== + */ + +/** + * A port is used to send or receive inter-isolate messages + */ +typedef int64_t Dart_Port; + +/** + * ILLEGAL_PORT is a port number guaranteed never to be associated with a valid + * port. + */ +#define ILLEGAL_PORT ((Dart_Port)0) + +/** + * A message notification callback. + * + * This callback allows the embedder to provide a custom wakeup mechanism for + * the delivery of inter-isolate messages. This function is called once per + * message on an arbitrary thread. It is the responsibility of the embedder to + * eventually call Dart_HandleMessage once per callback received with the + * destination isolate set as the current isolate to process the message. + */ +typedef void (*Dart_MessageNotifyCallback)(Dart_Isolate destination_isolate); + +/** + * Allows embedders to provide a custom wakeup mechanism for the delivery of + * inter-isolate messages. This setting only applies to the current isolate. + * + * This mechanism is optional: if not provided, the isolate will be scheduled on + * a VM-managed thread pool. An embedder should provide this callback if it + * wants to run an isolate on a specific thread or to interleave handling of + * inter-isolate messages with other event sources. + * + * Most embedders will only call this function once, before isolate + * execution begins. If this function is called after isolate + * execution begins, the embedder is responsible for threading issues. + */ +DART_EXPORT void Dart_SetMessageNotifyCallback( + Dart_MessageNotifyCallback message_notify_callback); +/* TODO(turnidge): Consider moving this to isolate creation so that it + * is impossible to mess up. */ + +/** + * Query the current message notify callback for the isolate. + * + * \return The current message notify callback for the isolate. + */ +DART_EXPORT Dart_MessageNotifyCallback Dart_GetMessageNotifyCallback(void); + +/** + * The VM's default message handler supports pausing an isolate before it + * processes the first message and right after the it processes the isolate's + * final message. This can be controlled for all isolates by two VM flags: + * + * `--pause-isolates-on-start` + * `--pause-isolates-on-exit` + * + * Additionally, Dart_SetShouldPauseOnStart and Dart_SetShouldPauseOnExit can be + * used to control this behaviour on a per-isolate basis. + * + * When an embedder is using a Dart_MessageNotifyCallback the embedder + * needs to cooperate with the VM so that the service protocol can report + * accurate information about isolates and so that tools such as debuggers + * work reliably. + * + * The following functions can be used to implement pausing on start and exit. + */ + +/** + * If the VM flag `--pause-isolates-on-start` was passed this will be true. + * + * \return A boolean value indicating if pause on start was requested. + */ +DART_EXPORT bool Dart_ShouldPauseOnStart(void); + +/** + * Override the VM flag `--pause-isolates-on-start` for the current isolate. + * + * \param should_pause Should the isolate be paused on start? + * + * NOTE: This must be called before Dart_IsolateMakeRunnable. + */ +DART_EXPORT void Dart_SetShouldPauseOnStart(bool should_pause); + +/** + * Is the current isolate paused on start? + * + * \return A boolean value indicating if the isolate is paused on start. + */ +DART_EXPORT bool Dart_IsPausedOnStart(void); + +/** + * Called when the embedder has paused the current isolate on start and when + * the embedder has resumed the isolate. + * + * \param paused Is the isolate paused on start? + */ +DART_EXPORT void Dart_SetPausedOnStart(bool paused); + +/** + * If the VM flag `--pause-isolates-on-exit` was passed this will be true. + * + * \return A boolean value indicating if pause on exit was requested. + */ +DART_EXPORT bool Dart_ShouldPauseOnExit(void); + +/** + * Override the VM flag `--pause-isolates-on-exit` for the current isolate. + * + * \param should_pause Should the isolate be paused on exit? + * + */ +DART_EXPORT void Dart_SetShouldPauseOnExit(bool should_pause); + +/** + * Is the current isolate paused on exit? + * + * \return A boolean value indicating if the isolate is paused on exit. + */ +DART_EXPORT bool Dart_IsPausedOnExit(void); + +/** + * Called when the embedder has paused the current isolate on exit and when + * the embedder has resumed the isolate. + * + * \param paused Is the isolate paused on exit? + */ +DART_EXPORT void Dart_SetPausedOnExit(bool paused); + +/** + * Called when the embedder has caught a top level unhandled exception error + * in the current isolate. + * + * NOTE: It is illegal to call this twice on the same isolate without first + * clearing the sticky error to null. + * + * \param error The unhandled exception error. + */ +DART_EXPORT void Dart_SetStickyError(Dart_Handle error); + +/** + * Does the current isolate have a sticky error? + */ +DART_EXPORT bool Dart_HasStickyError(void); + +/** + * Gets the sticky error for the current isolate. + * + * \return A handle to the sticky error object or null. + */ +DART_EXPORT Dart_Handle Dart_GetStickyError(void); + +/** + * Handles the next pending message for the current isolate. + * + * May generate an unhandled exception error. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_HandleMessage(void); + +/** + * Drains the microtask queue, then blocks the calling thread until the current + * isolate receives a message, then handles all messages. + * + * \param timeout_millis When non-zero, the call returns after the indicated + number of milliseconds even if no message was received. + * \return A valid handle if no error occurs, otherwise an error handle. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle +Dart_WaitForEvent(int64_t timeout_millis); + +/** + * Handles any pending messages for the vm service for the current + * isolate. + * + * This function may be used by an embedder at a breakpoint to avoid + * pausing the vm service. + * + * This function can indirectly cause the message notify callback to + * be called. + * + * \return true if the vm service requests the program resume + * execution, false otherwise + */ +DART_EXPORT bool Dart_HandleServiceMessages(void); + +/** + * Does the current isolate have pending service messages? + * + * \return true if the isolate has pending service messages, false otherwise. + */ +DART_EXPORT bool Dart_HasServiceMessages(void); + +/** + * Processes any incoming messages for the current isolate. + * + * This function may only be used when the embedder has not provided + * an alternate message delivery mechanism with + * Dart_SetMessageCallbacks. It is provided for convenience. + * + * This function waits for incoming messages for the current + * isolate. As new messages arrive, they are handled using + * Dart_HandleMessage. The routine exits when all ports to the + * current isolate are closed. + * + * \return A valid handle if the run loop exited successfully. If an + * exception or other error occurs while processing messages, an + * error handle is returned. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_RunLoop(void); + +/** + * Lets the VM run message processing for the isolate. + * + * This function expects there to a current isolate and the current isolate + * must not have an active api scope. The VM will take care of making the + * isolate runnable (if not already), handles its message loop and will take + * care of shutting the isolate down once it's done. + * + * \param errors_are_fatal Whether uncaught errors should be fatal. + * \param on_error_port A port to notify on uncaught errors (or ILLEGAL_PORT). + * \param on_exit_port A port to notify on exit (or ILLEGAL_PORT). + * \param error A non-NULL pointer which will hold an error message if the call + * fails. The error has to be free()ed by the caller. + * + * \return If successful the VM takes ownership of the isolate and takes care + * of its message loop. If not successful the caller retains ownership of the + * isolate. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT bool Dart_RunLoopAsync( + bool errors_are_fatal, + Dart_Port on_error_port, + Dart_Port on_exit_port, + char** error); + +/* TODO(turnidge): Should this be removed from the public api? */ + +/** + * Gets the main port id for the current isolate. + */ +DART_EXPORT Dart_Port Dart_GetMainPortId(void); + +/** + * Does the current isolate have live ReceivePorts? + * + * A ReceivePort is live when it has not been closed. + */ +DART_EXPORT bool Dart_HasLivePorts(void); + +/** + * Posts a message for some isolate. The message is a serialized + * object. + * + * Requires there to be a current isolate. + * + * For posting messages outside of an isolate see \ref Dart_PostCObject. + * + * \param port_id The destination port. + * \param object An object from the current isolate. + * + * \return True if the message was posted. + */ +DART_EXPORT bool Dart_Post(Dart_Port port_id, Dart_Handle object); + +/** + * Returns a new SendPort with the provided port id. + * + * \param port_id The destination port. + * + * \return A new SendPort if no errors occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_NewSendPort(Dart_Port port_id); + +/** + * Gets the SendPort id for the provided SendPort. + * \param port A SendPort object whose id is desired. + * \param port_id Returns the id of the SendPort. + * \return Success if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_SendPortGetId(Dart_Handle port, + Dart_Port* port_id); + +/* + * ====== + * Scopes + * ====== + */ + +/** + * Enters a new scope. + * + * All new local handles will be created in this scope. Additionally, + * some functions may return "scope allocated" memory which is only + * valid within this scope. + * + * Requires there to be a current isolate. + */ +DART_EXPORT void Dart_EnterScope(void); + +/** + * Exits a scope. + * + * The previous scope (if any) becomes the current scope. + * + * Requires there to be a current isolate. + */ +DART_EXPORT void Dart_ExitScope(void); + +/** + * The Dart VM uses "zone allocation" for temporary structures. Zones + * support very fast allocation of small chunks of memory. The chunks + * cannot be deallocated individually, but instead zones support + * deallocating all chunks in one fast operation. + * + * This function makes it possible for the embedder to allocate + * temporary data in the VMs zone allocator. + * + * Zone allocation is possible: + * 1. when inside a scope where local handles can be allocated + * 2. when processing a message from a native port in a native port + * handler + * + * All the memory allocated this way will be reclaimed either on the + * next call to Dart_ExitScope or when the native port handler exits. + * + * \param size Size of the memory to allocate. + * + * \return A pointer to the allocated memory. NULL if allocation + * failed. Failure might due to is no current VM zone. + */ +DART_EXPORT uint8_t* Dart_ScopeAllocate(intptr_t size); + +/* + * ======= + * Objects + * ======= + */ + +/** + * Returns the null object. + * + * \return A handle to the null object. + */ +DART_EXPORT Dart_Handle Dart_Null(void); + +/** + * Is this object null? + */ +DART_EXPORT bool Dart_IsNull(Dart_Handle object); + +/** + * Returns the empty string object. + * + * \return A handle to the empty string object. + */ +DART_EXPORT Dart_Handle Dart_EmptyString(void); + +/** + * Returns types that are not classes, and which therefore cannot be looked up + * as library members by Dart_GetType. + * + * \return A handle to the dynamic, void or Never type. + */ +DART_EXPORT Dart_Handle Dart_TypeDynamic(void); +DART_EXPORT Dart_Handle Dart_TypeVoid(void); +DART_EXPORT Dart_Handle Dart_TypeNever(void); + +/** + * Checks if the two objects are equal. + * + * The result of the comparison is returned through the 'equal' + * parameter. The return value itself is used to indicate success or + * failure, not equality. + * + * May generate an unhandled exception error. + * + * \param obj1 An object to be compared. + * \param obj2 An object to be compared. + * \param equal Returns the result of the equality comparison. + * + * \return A valid handle if no error occurs during the comparison. + */ +DART_EXPORT Dart_Handle Dart_ObjectEquals(Dart_Handle obj1, + Dart_Handle obj2, + bool* equal); + +/** + * Is this object an instance of some type? + * + * The result of the test is returned through the 'instanceof' parameter. + * The return value itself is used to indicate success or failure. + * + * \param object An object. + * \param type A type. + * \param instanceof Return true if 'object' is an instance of type 'type'. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_ObjectIsType(Dart_Handle object, + Dart_Handle type, + bool* instanceof); + +/** + * Query object type. + * + * \param object Some Object. + * + * \return true if Object is of the specified type. + */ +DART_EXPORT bool Dart_IsInstance(Dart_Handle object); +DART_EXPORT bool Dart_IsNumber(Dart_Handle object); +DART_EXPORT bool Dart_IsInteger(Dart_Handle object); +DART_EXPORT bool Dart_IsDouble(Dart_Handle object); +DART_EXPORT bool Dart_IsBoolean(Dart_Handle object); +DART_EXPORT bool Dart_IsString(Dart_Handle object); +DART_EXPORT bool Dart_IsStringLatin1(Dart_Handle object); /* (ISO-8859-1) */ +DART_EXPORT bool Dart_IsExternalString(Dart_Handle object); +DART_EXPORT bool Dart_IsList(Dart_Handle object); +DART_EXPORT bool Dart_IsMap(Dart_Handle object); +DART_EXPORT bool Dart_IsLibrary(Dart_Handle object); +DART_EXPORT bool Dart_IsType(Dart_Handle handle); +DART_EXPORT bool Dart_IsFunction(Dart_Handle handle); +DART_EXPORT bool Dart_IsVariable(Dart_Handle handle); +DART_EXPORT bool Dart_IsTypeVariable(Dart_Handle handle); +DART_EXPORT bool Dart_IsClosure(Dart_Handle object); +DART_EXPORT bool Dart_IsTypedData(Dart_Handle object); +DART_EXPORT bool Dart_IsByteBuffer(Dart_Handle object); +DART_EXPORT bool Dart_IsFuture(Dart_Handle object); + +/* + * ========= + * Instances + * ========= + */ + +/* + * For the purposes of the embedding api, not all objects returned are + * Dart language objects. Within the api, we use the term 'Instance' + * to indicate handles which refer to true Dart language objects. + * + * TODO(turnidge): Reorganize the "Object" section above, pulling down + * any functions that more properly belong here. */ + +/** + * Gets the type of a Dart language object. + * + * \param instance Some Dart object. + * + * \return If no error occurs, the type is returned. Otherwise an + * error handle is returned. + */ +DART_EXPORT Dart_Handle Dart_InstanceGetType(Dart_Handle instance); + +/** + * Returns the name for the provided class type. + * + * \return A valid string handle if no error occurs during the + * operation. + */ +DART_EXPORT Dart_Handle Dart_ClassName(Dart_Handle cls_type); + +/** + * Returns the name for the provided function or method. + * + * \return A valid string handle if no error occurs during the + * operation. + */ +DART_EXPORT Dart_Handle Dart_FunctionName(Dart_Handle function); + +/** + * Returns a handle to the owner of a function. + * + * The owner of an instance method or a static method is its defining + * class. The owner of a top-level function is its defining + * library. The owner of the function of a non-implicit closure is the + * function of the method or closure that defines the non-implicit + * closure. + * + * \return A valid handle to the owner of the function, or an error + * handle if the argument is not a valid handle to a function. + */ +DART_EXPORT Dart_Handle Dart_FunctionOwner(Dart_Handle function); + +/** + * Determines whether a function handle refers to a static function + * of method. + * + * For the purposes of the embedding API, a top-level function is + * implicitly declared static. + * + * \param function A handle to a function or method declaration. + * \param is_static Returns whether the function or method is declared static. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_FunctionIsStatic(Dart_Handle function, + bool* is_static); + +/** + * Is this object a closure resulting from a tear-off (closurized method)? + * + * Returns true for closures produced when an ordinary method is accessed + * through a getter call. Returns false otherwise, in particular for closures + * produced from local function declarations. + * + * \param object Some Object. + * + * \return true if Object is a tear-off. + */ +DART_EXPORT bool Dart_IsTearOff(Dart_Handle object); + +/** + * Retrieves the function of a closure. + * + * \return A handle to the function of the closure, or an error handle if the + * argument is not a closure. + */ +DART_EXPORT Dart_Handle Dart_ClosureFunction(Dart_Handle closure); + +/** + * Returns a handle to the library which contains class. + * + * \return A valid handle to the library with owns class, null if the class + * has no library or an error handle if the argument is not a valid handle + * to a class type. + */ +DART_EXPORT Dart_Handle Dart_ClassLibrary(Dart_Handle cls_type); + +/* + * ============================= + * Numbers, Integers and Doubles + * ============================= + */ + +/** + * Does this Integer fit into a 64-bit signed integer? + * + * \param integer An integer. + * \param fits Returns true if the integer fits into a 64-bit signed integer. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_IntegerFitsIntoInt64(Dart_Handle integer, + bool* fits); + +/** + * Does this Integer fit into a 64-bit unsigned integer? + * + * \param integer An integer. + * \param fits Returns true if the integer fits into a 64-bit unsigned integer. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_IntegerFitsIntoUint64(Dart_Handle integer, + bool* fits); + +/** + * Returns an Integer with the provided value. + * + * \param value The value of the integer. + * + * \return The Integer object if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_NewInteger(int64_t value); + +/** + * Returns an Integer with the provided value. + * + * \param value The unsigned value of the integer. + * + * \return The Integer object if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_NewIntegerFromUint64(uint64_t value); + +/** + * Returns an Integer with the provided value. + * + * \param value The value of the integer represented as a C string + * containing a hexadecimal number. + * + * \return The Integer object if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_NewIntegerFromHexCString(const char* value); + +/** + * Gets the value of an Integer. + * + * The integer must fit into a 64-bit signed integer, otherwise an error occurs. + * + * \param integer An Integer. + * \param value Returns the value of the Integer. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_IntegerToInt64(Dart_Handle integer, + int64_t* value); + +/** + * Gets the value of an Integer. + * + * The integer must fit into a 64-bit unsigned integer, otherwise an + * error occurs. + * + * \param integer An Integer. + * \param value Returns the value of the Integer. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_IntegerToUint64(Dart_Handle integer, + uint64_t* value); + +/** + * Gets the value of an integer as a hexadecimal C string. + * + * \param integer An Integer. + * \param value Returns the value of the Integer as a hexadecimal C + * string. This C string is scope allocated and is only valid until + * the next call to Dart_ExitScope. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_IntegerToHexCString(Dart_Handle integer, + const char** value); + +/** + * Returns a Double with the provided value. + * + * \param value A double. + * + * \return The Double object if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_NewDouble(double value); + +/** + * Gets the value of a Double + * + * \param double_obj A Double + * \param value Returns the value of the Double. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_DoubleValue(Dart_Handle double_obj, double* value); + +/** + * Returns a closure of static function 'function_name' in the class 'class_name' + * in the exported namespace of specified 'library'. + * + * \param library Library object + * \param cls_type Type object representing a Class + * \param function_name Name of the static function in the class + * + * \return A valid Dart instance if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_GetStaticMethodClosure(Dart_Handle library, + Dart_Handle cls_type, + Dart_Handle function_name); + +/* + * ======== + * Booleans + * ======== + */ + +/** + * Returns the True object. + * + * Requires there to be a current isolate. + * + * \return A handle to the True object. + */ +DART_EXPORT Dart_Handle Dart_True(void); + +/** + * Returns the False object. + * + * Requires there to be a current isolate. + * + * \return A handle to the False object. + */ +DART_EXPORT Dart_Handle Dart_False(void); + +/** + * Returns a Boolean with the provided value. + * + * \param value true or false. + * + * \return The Boolean object if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_NewBoolean(bool value); + +/** + * Gets the value of a Boolean + * + * \param boolean_obj A Boolean + * \param value Returns the value of the Boolean. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_BooleanValue(Dart_Handle boolean_obj, bool* value); + +/* + * ======= + * Strings + * ======= + */ + +/** + * Gets the length of a String. + * + * \param str A String. + * \param length Returns the length of the String. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_StringLength(Dart_Handle str, intptr_t* length); + +/** + * Returns a String built from the provided C string + * (There is an implicit assumption that the C string passed in contains + * UTF-8 encoded characters and '\0' is considered as a termination + * character). + * + * \param str A C String + * + * \return The String object if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_NewStringFromCString(const char* str); +/* TODO(turnidge): Document what happens when we run out of memory + * during this call. */ + +/** + * Returns a String built from an array of UTF-8 encoded characters. + * + * \param utf8_array An array of UTF-8 encoded characters. + * \param length The length of the codepoints array. + * + * \return The String object if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_NewStringFromUTF8(const uint8_t* utf8_array, + intptr_t length); + +/** + * Returns a String built from an array of UTF-16 encoded characters. + * + * \param utf16_array An array of UTF-16 encoded characters. + * \param length The length of the codepoints array. + * + * \return The String object if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_NewStringFromUTF16(const uint16_t* utf16_array, + intptr_t length); + +/** + * Returns a String built from an array of UTF-32 encoded characters. + * + * \param utf32_array An array of UTF-32 encoded characters. + * \param length The length of the codepoints array. + * + * \return The String object if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_NewStringFromUTF32(const int32_t* utf32_array, + intptr_t length); + +/** + * Returns a String which references an external array of + * Latin-1 (ISO-8859-1) encoded characters. + * + * \param latin1_array Array of Latin-1 encoded characters. This must not move. + * \param length The length of the characters array. + * \param peer An external pointer to associate with this string. + * \param external_allocation_size The number of externally allocated + * bytes for peer. Used to inform the garbage collector. + * \param callback A callback to be called when this string is finalized. + * + * \return The String object if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle +Dart_NewExternalLatin1String(const uint8_t* latin1_array, + intptr_t length, + void* peer, + intptr_t external_allocation_size, + Dart_HandleFinalizer callback); + +/** + * Returns a String which references an external array of UTF-16 encoded + * characters. + * + * \param utf16_array An array of UTF-16 encoded characters. This must not move. + * \param length The length of the characters array. + * \param peer An external pointer to associate with this string. + * \param external_allocation_size The number of externally allocated + * bytes for peer. Used to inform the garbage collector. + * \param callback A callback to be called when this string is finalized. + * + * \return The String object if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle +Dart_NewExternalUTF16String(const uint16_t* utf16_array, + intptr_t length, + void* peer, + intptr_t external_allocation_size, + Dart_HandleFinalizer callback); + +/** + * Gets the C string representation of a String. + * (It is a sequence of UTF-8 encoded values with a '\0' termination.) + * + * \param str A string. + * \param cstr Returns the String represented as a C string. + * This C string is scope allocated and is only valid until + * the next call to Dart_ExitScope. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_StringToCString(Dart_Handle str, + const char** cstr); + +/** + * Gets a UTF-8 encoded representation of a String. + * + * Any unpaired surrogate code points in the string will be converted as + * replacement characters (U+FFFD, 0xEF 0xBF 0xBD in UTF-8). If you need + * to preserve unpaired surrogates, use the Dart_StringToUTF16 function. + * + * \param str A string. + * \param utf8_array Returns the String represented as UTF-8 code + * units. This UTF-8 array is scope allocated and is only valid + * until the next call to Dart_ExitScope. + * \param length Used to return the length of the array which was + * actually used. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_StringToUTF8(Dart_Handle str, + uint8_t** utf8_array, + intptr_t* length); + +/** + * Gets the data corresponding to the string object. This function returns + * the data only for Latin-1 (ISO-8859-1) string objects. For all other + * string objects it returns an error. + * + * \param str A string. + * \param latin1_array An array allocated by the caller, used to return + * the string data. + * \param length Used to pass in the length of the provided array. + * Used to return the length of the array which was actually used. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_StringToLatin1(Dart_Handle str, + uint8_t* latin1_array, + intptr_t* length); + +/** + * Gets the UTF-16 encoded representation of a string. + * + * \param str A string. + * \param utf16_array An array allocated by the caller, used to return + * the array of UTF-16 encoded characters. + * \param length Used to pass in the length of the provided array. + * Used to return the length of the array which was actually used. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_StringToUTF16(Dart_Handle str, + uint16_t* utf16_array, + intptr_t* length); + +/** + * Gets the storage size in bytes of a String. + * + * \param str A String. + * \param size Returns the storage size in bytes of the String. + * This is the size in bytes needed to store the String. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_StringStorageSize(Dart_Handle str, intptr_t* size); + +/** + * Retrieves some properties associated with a String. + * Properties retrieved are: + * - character size of the string (one or two byte) + * - length of the string + * - peer pointer of string if it is an external string. + * \param str A String. + * \param char_size Returns the character size of the String. + * \param str_len Returns the length of the String. + * \param peer Returns the peer pointer associated with the String or 0 if + * there is no peer pointer for it. + * \return Success if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_StringGetProperties(Dart_Handle str, + intptr_t* char_size, + intptr_t* str_len, + void** peer); + +/* + * ===== + * Lists + * ===== + */ + +/** + * Returns a List of the desired length. + * + * \param length The length of the list. + * + * \return The List object if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_NewList(intptr_t length); + +typedef enum { + Dart_CoreType_Dynamic, + Dart_CoreType_Int, + Dart_CoreType_String, +} Dart_CoreType_Id; + +// TODO(bkonyi): convert this to use nullable types once NNBD is enabled. +/** + * Returns a List of the desired length with the desired legacy element type. + * + * \param element_type_id The type of elements of the list. + * \param length The length of the list. + * + * \return The List object if no error occurs. Otherwise returns an error + * handle. + */ +DART_EXPORT Dart_Handle Dart_NewListOf(Dart_CoreType_Id element_type_id, + intptr_t length); + +/** + * Returns a List of the desired length with the desired element type. + * + * \param element_type Handle to a nullable type object. E.g., from + * Dart_GetType or Dart_GetNullableType. + * + * \param length The length of the list. + * + * \return The List object if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_NewListOfType(Dart_Handle element_type, + intptr_t length); + +/** + * Returns a List of the desired length with the desired element type, filled + * with the provided object. + * + * \param element_type Handle to a type object. E.g., from Dart_GetType. + * + * \param fill_object Handle to an object of type 'element_type' that will be + * used to populate the list. This parameter can only be Dart_Null() if the + * length of the list is 0 or 'element_type' is a nullable type. + * + * \param length The length of the list. + * + * \return The List object if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_NewListOfTypeFilled(Dart_Handle element_type, + Dart_Handle fill_object, + intptr_t length); + +/** + * Gets the length of a List. + * + * May generate an unhandled exception error. + * + * \param list A List. + * \param length Returns the length of the List. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_ListLength(Dart_Handle list, intptr_t* length); + +/** + * Gets the Object at some index of a List. + * + * If the index is out of bounds, an error occurs. + * + * May generate an unhandled exception error. + * + * \param list A List. + * \param index A valid index into the List. + * + * \return The Object in the List at the specified index if no error + * occurs. Otherwise returns an error handle. + */ +DART_EXPORT Dart_Handle Dart_ListGetAt(Dart_Handle list, intptr_t index); + +/** +* Gets a range of Objects from a List. +* +* If any of the requested index values are out of bounds, an error occurs. +* +* May generate an unhandled exception error. +* +* \param list A List. +* \param offset The offset of the first item to get. +* \param length The number of items to get. +* \param result A pointer to fill with the objects. +* +* \return Success if no error occurs during the operation. +*/ +DART_EXPORT Dart_Handle Dart_ListGetRange(Dart_Handle list, + intptr_t offset, + intptr_t length, + Dart_Handle* result); + +/** + * Sets the Object at some index of a List. + * + * If the index is out of bounds, an error occurs. + * + * May generate an unhandled exception error. + * + * \param list A List. + * \param index A valid index into the List. + * \param value The Object to put in the List. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_ListSetAt(Dart_Handle list, + intptr_t index, + Dart_Handle value); + +/** + * May generate an unhandled exception error. + */ +DART_EXPORT Dart_Handle Dart_ListGetAsBytes(Dart_Handle list, + intptr_t offset, + uint8_t* native_array, + intptr_t length); + +/** + * May generate an unhandled exception error. + */ +DART_EXPORT Dart_Handle Dart_ListSetAsBytes(Dart_Handle list, + intptr_t offset, + const uint8_t* native_array, + intptr_t length); + +/* + * ==== + * Maps + * ==== + */ + +/** + * Gets the Object at some key of a Map. + * + * May generate an unhandled exception error. + * + * \param map A Map. + * \param key An Object. + * + * \return The value in the map at the specified key, null if the map does not + * contain the key, or an error handle. + */ +DART_EXPORT Dart_Handle Dart_MapGetAt(Dart_Handle map, Dart_Handle key); + +/** + * Returns whether the Map contains a given key. + * + * May generate an unhandled exception error. + * + * \param map A Map. + * + * \return A handle on a boolean indicating whether map contains the key. + * Otherwise returns an error handle. + */ +DART_EXPORT Dart_Handle Dart_MapContainsKey(Dart_Handle map, Dart_Handle key); + +/** + * Gets the list of keys of a Map. + * + * May generate an unhandled exception error. + * + * \param map A Map. + * + * \return The list of key Objects if no error occurs. Otherwise returns an + * error handle. + */ +DART_EXPORT Dart_Handle Dart_MapKeys(Dart_Handle map); + +/* + * ========== + * Typed Data + * ========== + */ + +typedef enum { + Dart_TypedData_kByteData = 0, + Dart_TypedData_kInt8, + Dart_TypedData_kUint8, + Dart_TypedData_kUint8Clamped, + Dart_TypedData_kInt16, + Dart_TypedData_kUint16, + Dart_TypedData_kInt32, + Dart_TypedData_kUint32, + Dart_TypedData_kInt64, + Dart_TypedData_kUint64, + Dart_TypedData_kFloat32, + Dart_TypedData_kFloat64, + Dart_TypedData_kInt32x4, + Dart_TypedData_kFloat32x4, + Dart_TypedData_kFloat64x2, + Dart_TypedData_kInvalid +} Dart_TypedData_Type; + +/** + * Return type if this object is a TypedData object. + * + * \return kInvalid if the object is not a TypedData object or the appropriate + * Dart_TypedData_Type. + */ +DART_EXPORT Dart_TypedData_Type Dart_GetTypeOfTypedData(Dart_Handle object); + +/** + * Return type if this object is an external TypedData object. + * + * \return kInvalid if the object is not an external TypedData object or + * the appropriate Dart_TypedData_Type. + */ +DART_EXPORT Dart_TypedData_Type +Dart_GetTypeOfExternalTypedData(Dart_Handle object); + +/** + * Returns a TypedData object of the desired length and type. + * + * \param type The type of the TypedData object. + * \param length The length of the TypedData object (length in type units). + * + * \return The TypedData object if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_NewTypedData(Dart_TypedData_Type type, + intptr_t length); + +/** + * Returns a TypedData object which references an external data array. + * + * \param type The type of the data array. + * \param data A data array. This array must not move. + * \param length The length of the data array (length in type units). + * + * \return The TypedData object if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_NewExternalTypedData(Dart_TypedData_Type type, + void* data, + intptr_t length); + +/** + * Returns a TypedData object which references an external data array. + * + * \param type The type of the data array. + * \param data A data array. This array must not move. + * \param length The length of the data array (length in type units). + * \param peer A pointer to a native object or NULL. This value is + * provided to callback when it is invoked. + * \param external_allocation_size The number of externally allocated + * bytes for peer. Used to inform the garbage collector. + * \param callback A function pointer that will be invoked sometime + * after the object is garbage collected, unless the handle has been deleted. + * A valid callback needs to be specified it cannot be NULL. + * + * \return The TypedData object if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle +Dart_NewExternalTypedDataWithFinalizer(Dart_TypedData_Type type, + void* data, + intptr_t length, + void* peer, + intptr_t external_allocation_size, + Dart_HandleFinalizer callback); +DART_EXPORT Dart_Handle Dart_NewUnmodifiableExternalTypedDataWithFinalizer( + Dart_TypedData_Type type, + const void* data, + intptr_t length, + void* peer, + intptr_t external_allocation_size, + Dart_HandleFinalizer callback); + +/** + * Returns a ByteBuffer object for the typed data. + * + * \param typed_data The TypedData object. + * + * \return The ByteBuffer object if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_NewByteBuffer(Dart_Handle typed_data); + +/** + * Acquires access to the internal data address of a TypedData object. + * + * \param object The typed data object whose internal data address is to + * be accessed. + * \param type The type of the object is returned here. + * \param data The internal data address is returned here. + * \param len Size of the typed array is returned here. + * + * Notes: + * When the internal address of the object is acquired any calls to a + * Dart API function that could potentially allocate an object or run + * any Dart code will return an error. + * + * Any Dart API functions for accessing the data should not be called + * before the corresponding release. In particular, the object should + * not be acquired again before its release. This leads to undefined + * behavior. + * + * \return Success if the internal data address is acquired successfully. + * Otherwise, returns an error handle. + */ +DART_EXPORT Dart_Handle Dart_TypedDataAcquireData(Dart_Handle object, + Dart_TypedData_Type* type, + void** data, + intptr_t* len); + +/** + * Releases access to the internal data address that was acquired earlier using + * Dart_TypedDataAcquireData. + * + * \param object The typed data object whose internal data address is to be + * released. + * + * \return Success if the internal data address is released successfully. + * Otherwise, returns an error handle. + */ +DART_EXPORT Dart_Handle Dart_TypedDataReleaseData(Dart_Handle object); + +/** + * Returns the TypedData object associated with the ByteBuffer object. + * + * \param byte_buffer The ByteBuffer object. + * + * \return The TypedData object if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_GetDataFromByteBuffer(Dart_Handle byte_buffer); + +/* + * ============================================================ + * Invoking Constructors, Methods, Closures and Field accessors + * ============================================================ + */ + +/** + * Invokes a constructor, creating a new object. + * + * This function allows hidden constructors (constructors with leading + * underscores) to be called. + * + * \param type Type of object to be constructed. + * \param constructor_name The name of the constructor to invoke. Use + * Dart_Null() or Dart_EmptyString() to invoke the unnamed constructor. + * This name should not include the name of the class. + * \param number_of_arguments Size of the arguments array. + * \param arguments An array of arguments to the constructor. + * + * \return If the constructor is called and completes successfully, + * then the new object. If an error occurs during execution, then an + * error handle is returned. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle +Dart_New(Dart_Handle type, + Dart_Handle constructor_name, + int number_of_arguments, + Dart_Handle* arguments); + +/** + * Allocate a new object without invoking a constructor. + * + * \param type The type of an object to be allocated. + * + * \return The new object. If an error occurs during execution, then an + * error handle is returned. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_Allocate(Dart_Handle type); + +/** + * Allocate a new object without invoking a constructor, and sets specified + * native fields. + * + * \param type The type of an object to be allocated. + * \param num_native_fields The number of native fields to set. + * \param native_fields An array containing the value of native fields. + * + * \return The new object. If an error occurs during execution, then an + * error handle is returned. + */ +DART_EXPORT Dart_Handle +Dart_AllocateWithNativeFields(Dart_Handle type, + intptr_t num_native_fields, + const intptr_t* native_fields); + +/** + * Invokes a method or function. + * + * The 'target' parameter may be an object, type, or library. If + * 'target' is an object, then this function will invoke an instance + * method. If 'target' is a type, then this function will invoke a + * static method. If 'target' is a library, then this function will + * invoke a top-level function from that library. + * NOTE: This API call cannot be used to invoke methods of a type object. + * + * This function ignores visibility (leading underscores in names). + * + * May generate an unhandled exception error. + * + * \param target An object, type, or library. + * \param name The name of the function or method to invoke. + * \param number_of_arguments Size of the arguments array. + * \param arguments An array of arguments to the function. + * + * \return If the function or method is called and completes + * successfully, then the return value is returned. If an error + * occurs during execution, then an error handle is returned. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle +Dart_Invoke(Dart_Handle target, + Dart_Handle name, + int number_of_arguments, + Dart_Handle* arguments); +/* TODO(turnidge): Document how to invoke operators. */ + +/** + * Invokes a Closure with the given arguments. + * + * May generate an unhandled exception error. + * + * \return If no error occurs during execution, then the result of + * invoking the closure is returned. If an error occurs during + * execution, then an error handle is returned. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle +Dart_InvokeClosure(Dart_Handle closure, + int number_of_arguments, + Dart_Handle* arguments); + +/** + * Invokes a Generative Constructor on an object that was previously + * allocated using Dart_Allocate/Dart_AllocateWithNativeFields. + * + * The 'object' parameter must be an object. + * + * This function ignores visibility (leading underscores in names). + * + * May generate an unhandled exception error. + * + * \param object An object. + * \param name The name of the constructor to invoke. + * Use Dart_Null() or Dart_EmptyString() to invoke the unnamed constructor. + * \param number_of_arguments Size of the arguments array. + * \param arguments An array of arguments to the function. + * + * \return If the constructor is called and completes + * successfully, then the object is returned. If an error + * occurs during execution, then an error handle is returned. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle +Dart_InvokeConstructor(Dart_Handle object, + Dart_Handle name, + int number_of_arguments, + Dart_Handle* arguments); + +/** + * Gets the value of a field. + * + * The 'container' parameter may be an object, type, or library. If + * 'container' is an object, then this function will access an + * instance field. If 'container' is a type, then this function will + * access a static field. If 'container' is a library, then this + * function will access a top-level variable. + * NOTE: This API call cannot be used to access fields of a type object. + * + * This function ignores field visibility (leading underscores in names). + * + * May generate an unhandled exception error. + * + * \param container An object, type, or library. + * \param name A field name. + * + * \return If no error occurs, then the value of the field is + * returned. Otherwise an error handle is returned. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle +Dart_GetField(Dart_Handle container, Dart_Handle name); + +/** + * Sets the value of a field. + * + * The 'container' parameter may actually be an object, type, or + * library. If 'container' is an object, then this function will + * access an instance field. If 'container' is a type, then this + * function will access a static field. If 'container' is a library, + * then this function will access a top-level variable. + * NOTE: This API call cannot be used to access fields of a type object. + * + * This function ignores field visibility (leading underscores in names). + * + * May generate an unhandled exception error. + * + * \param container An object, type, or library. + * \param name A field name. + * \param value The new field value. + * + * \return A valid handle if no error occurs. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle +Dart_SetField(Dart_Handle container, Dart_Handle name, Dart_Handle value); + +/* + * ========== + * Exceptions + * ========== + */ + +/* + * TODO(turnidge): Remove these functions from the api and replace all + * uses with Dart_NewUnhandledExceptionError. */ + +/** + * Throws an exception. + * + * This function causes a Dart language exception to be thrown. This + * will proceed in the standard way, walking up Dart frames until an + * appropriate 'catch' block is found, executing 'finally' blocks, + * etc. + * + * If an error handle is passed into this function, the error is + * propagated immediately. See Dart_PropagateError for a discussion + * of error propagation. + * + * If successful, this function does not return. Note that this means + * that the destructors of any stack-allocated C++ objects will not be + * called. If there are no Dart frames on the stack, an error occurs. + * + * \return An error handle if the exception was not thrown. + * Otherwise the function does not return. + */ +DART_EXPORT Dart_Handle Dart_ThrowException(Dart_Handle exception); + +/** + * Rethrows an exception. + * + * Rethrows an exception, unwinding all dart frames on the stack. If + * successful, this function does not return. Note that this means + * that the destructors of any stack-allocated C++ objects will not be + * called. If there are no Dart frames on the stack, an error occurs. + * + * \return An error handle if the exception was not thrown. + * Otherwise the function does not return. + */ +DART_EXPORT Dart_Handle Dart_ReThrowException(Dart_Handle exception, + Dart_Handle stacktrace); + +/* + * =========================== + * Native fields and functions + * =========================== + */ + +/** + * Gets the number of native instance fields in an object. + */ +DART_EXPORT Dart_Handle Dart_GetNativeInstanceFieldCount(Dart_Handle obj, + int* count); + +/** + * Gets the value of a native field. + * + * TODO(turnidge): Document. + */ +DART_EXPORT Dart_Handle Dart_GetNativeInstanceField(Dart_Handle obj, + int index, + intptr_t* value); + +/** + * Sets the value of a native field. + * + * TODO(turnidge): Document. + */ +DART_EXPORT Dart_Handle Dart_SetNativeInstanceField(Dart_Handle obj, + int index, + intptr_t value); + +/** + * The arguments to a native function. + * + * This object is passed to a native function to represent its + * arguments and return value. It allows access to the arguments to a + * native function by index. It also allows the return value of a + * native function to be set. + */ +typedef struct _Dart_NativeArguments* Dart_NativeArguments; + +/** + * Extracts current isolate group data from the native arguments structure. + */ +DART_EXPORT void* Dart_GetNativeIsolateGroupData(Dart_NativeArguments args); + +typedef enum { + Dart_NativeArgument_kBool = 0, + Dart_NativeArgument_kInt32, + Dart_NativeArgument_kUint32, + Dart_NativeArgument_kInt64, + Dart_NativeArgument_kUint64, + Dart_NativeArgument_kDouble, + Dart_NativeArgument_kString, + Dart_NativeArgument_kInstance, + Dart_NativeArgument_kNativeFields, +} Dart_NativeArgument_Type; + +typedef struct _Dart_NativeArgument_Descriptor { + uint8_t type; + uint8_t index; +} Dart_NativeArgument_Descriptor; + +typedef union _Dart_NativeArgument_Value { + bool as_bool; + int32_t as_int32; + uint32_t as_uint32; + int64_t as_int64; + uint64_t as_uint64; + double as_double; + struct { + Dart_Handle dart_str; + void* peer; + } as_string; + struct { + intptr_t num_fields; + intptr_t* values; + } as_native_fields; + Dart_Handle as_instance; +} Dart_NativeArgument_Value; + +enum { + kNativeArgNumberPos = 0, + kNativeArgNumberSize = 8, + kNativeArgTypePos = kNativeArgNumberPos + kNativeArgNumberSize, + kNativeArgTypeSize = 8, +}; + +#define BITMASK(size) ((1 << size) - 1) +#define DART_NATIVE_ARG_DESCRIPTOR(type, position) \ + (((type & BITMASK(kNativeArgTypeSize)) << kNativeArgTypePos) | \ + (position & BITMASK(kNativeArgNumberSize))) + +/** + * Gets the native arguments based on the types passed in and populates + * the passed arguments buffer with appropriate native values. + * + * \param args the Native arguments block passed into the native call. + * \param num_arguments length of argument descriptor array and argument + * values array passed in. + * \param arg_descriptors an array that describes the arguments that + * need to be retrieved. For each argument to be retrieved the descriptor + * contains the argument number (0, 1 etc.) and the argument type + * described using Dart_NativeArgument_Type, e.g: + * DART_NATIVE_ARG_DESCRIPTOR(Dart_NativeArgument_kBool, 1) indicates + * that the first argument is to be retrieved and it should be a boolean. + * \param arg_values array into which the native arguments need to be + * extracted into, the array is allocated by the caller (it could be + * stack allocated to avoid the malloc/free performance overhead). + * + * \return Success if all the arguments could be extracted correctly, + * returns an error handle if there were any errors while extracting the + * arguments (mismatched number of arguments, incorrect types, etc.). + */ +DART_EXPORT Dart_Handle +Dart_GetNativeArguments(Dart_NativeArguments args, + int num_arguments, + const Dart_NativeArgument_Descriptor* arg_descriptors, + Dart_NativeArgument_Value* arg_values); + +/** + * Gets the native argument at some index. + */ +DART_EXPORT Dart_Handle Dart_GetNativeArgument(Dart_NativeArguments args, + int index); +/* TODO(turnidge): Specify the behavior of an out-of-bounds access. */ + +/** + * Gets the number of native arguments. + */ +DART_EXPORT int Dart_GetNativeArgumentCount(Dart_NativeArguments args); + +/** + * Gets all the native fields of the native argument at some index. + * \param args Native arguments structure. + * \param arg_index Index of the desired argument in the structure above. + * \param num_fields size of the intptr_t array 'field_values' passed in. + * \param field_values intptr_t array in which native field values are returned. + * \return Success if the native fields where copied in successfully. Otherwise + * returns an error handle. On success the native field values are copied + * into the 'field_values' array, if the argument at 'arg_index' is a + * null object then 0 is copied as the native field values into the + * 'field_values' array. + */ +DART_EXPORT Dart_Handle +Dart_GetNativeFieldsOfArgument(Dart_NativeArguments args, + int arg_index, + int num_fields, + intptr_t* field_values); + +/** + * Gets the native field of the receiver. + */ +DART_EXPORT Dart_Handle Dart_GetNativeReceiver(Dart_NativeArguments args, + intptr_t* value); + +/** + * Gets a string native argument at some index. + * \param args Native arguments structure. + * \param arg_index Index of the desired argument in the structure above. + * \param peer Returns the peer pointer if the string argument has one. + * \return Success if the string argument has a peer, if it does not + * have a peer then the String object is returned. Otherwise returns + * an error handle (argument is not a String object). + */ +DART_EXPORT Dart_Handle Dart_GetNativeStringArgument(Dart_NativeArguments args, + int arg_index, + void** peer); + +/** + * Gets an integer native argument at some index. + * \param args Native arguments structure. + * \param index Index of the desired argument in the structure above. + * \param value Returns the integer value if the argument is an Integer. + * \return Success if no error occurs. Otherwise returns an error handle. + */ +DART_EXPORT Dart_Handle Dart_GetNativeIntegerArgument(Dart_NativeArguments args, + int index, + int64_t* value); + +/** + * Gets a boolean native argument at some index. + * \param args Native arguments structure. + * \param index Index of the desired argument in the structure above. + * \param value Returns the boolean value if the argument is a Boolean. + * \return Success if no error occurs. Otherwise returns an error handle. + */ +DART_EXPORT Dart_Handle Dart_GetNativeBooleanArgument(Dart_NativeArguments args, + int index, + bool* value); + +/** + * Gets a double native argument at some index. + * \param args Native arguments structure. + * \param index Index of the desired argument in the structure above. + * \param value Returns the double value if the argument is a double. + * \return Success if no error occurs. Otherwise returns an error handle. + */ +DART_EXPORT Dart_Handle Dart_GetNativeDoubleArgument(Dart_NativeArguments args, + int index, + double* value); + +/** + * Sets the return value for a native function. + * + * If retval is an Error handle, then error will be propagated once + * the native functions exits. See Dart_PropagateError for a + * discussion of how different types of errors are propagated. + */ +DART_EXPORT void Dart_SetReturnValue(Dart_NativeArguments args, + Dart_Handle retval); + +DART_EXPORT void Dart_SetWeakHandleReturnValue(Dart_NativeArguments args, + Dart_WeakPersistentHandle rval); + +DART_EXPORT void Dart_SetBooleanReturnValue(Dart_NativeArguments args, + bool retval); + +DART_EXPORT void Dart_SetIntegerReturnValue(Dart_NativeArguments args, + int64_t retval); + +DART_EXPORT void Dart_SetDoubleReturnValue(Dart_NativeArguments args, + double retval); + +/** + * A native function. + */ +typedef void (*Dart_NativeFunction)(Dart_NativeArguments arguments); + +/** + * Native entry resolution callback. + * + * For libraries and scripts which have native functions, the embedder + * can provide a native entry resolver. This callback is used to map a + * name/arity to a Dart_NativeFunction. If no function is found, the + * callback should return NULL. + * + * The parameters to the native resolver function are: + * \param name a Dart string which is the name of the native function. + * \param num_of_arguments is the number of arguments expected by the + * native function. + * \param auto_setup_scope is a boolean flag that can be set by the resolver + * to indicate if this function needs a Dart API scope (see Dart_EnterScope/ + * Dart_ExitScope) to be setup automatically by the VM before calling into + * the native function. By default most native functions would require this + * to be true but some light weight native functions which do not call back + * into the VM through the Dart API may not require a Dart scope to be + * setup automatically. + * + * \return A valid Dart_NativeFunction which resolves to a native entry point + * for the native function. + * + * See Dart_SetNativeResolver. + */ +typedef Dart_NativeFunction (*Dart_NativeEntryResolver)(Dart_Handle name, + int num_of_arguments, + bool* auto_setup_scope); +/* TODO(turnidge): Consider renaming to NativeFunctionResolver or + * NativeResolver. */ + +/** + * Native entry symbol lookup callback. + * + * For libraries and scripts which have native functions, the embedder + * can provide a callback for mapping a native entry to a symbol. This callback + * maps a native function entry PC to the native function name. If no native + * entry symbol can be found, the callback should return NULL. + * + * The parameters to the native reverse resolver function are: + * \param nf A Dart_NativeFunction. + * + * \return A const UTF-8 string containing the symbol name or NULL. + * + * See Dart_SetNativeResolver. + */ +typedef const uint8_t* (*Dart_NativeEntrySymbol)(Dart_NativeFunction nf); + +/** + * FFI Native C function pointer resolver callback. + * + * See Dart_SetFfiNativeResolver. + */ +typedef void* (*Dart_FfiNativeResolver)(const char* name, uintptr_t args_n); + +/* + * =========== + * Environment + * =========== + */ + +/** + * An environment lookup callback function. + * + * \param name The name of the value to lookup in the environment. + * + * \return A valid handle to a string if the name exists in the + * current environment or Dart_Null() if not. + */ +typedef Dart_Handle (*Dart_EnvironmentCallback)(Dart_Handle name); + +/** + * Sets the environment callback for the current isolate. This + * callback is used to lookup environment values by name in the + * current environment. This enables the embedder to supply values for + * the const constructors bool.fromEnvironment, int.fromEnvironment + * and String.fromEnvironment. + */ +DART_EXPORT Dart_Handle +Dart_SetEnvironmentCallback(Dart_EnvironmentCallback callback); + +/** + * Sets the callback used to resolve native functions for a library. + * + * \param library A library. + * \param resolver A native entry resolver. + * + * \return A valid handle if the native resolver was set successfully. + */ +DART_EXPORT Dart_Handle +Dart_SetNativeResolver(Dart_Handle library, + Dart_NativeEntryResolver resolver, + Dart_NativeEntrySymbol symbol); +/* TODO(turnidge): Rename to Dart_LibrarySetNativeResolver? */ + +/** + * Returns the callback used to resolve native functions for a library. + * + * \param library A library. + * \param resolver a pointer to a Dart_NativeEntryResolver + * + * \return A valid handle if the library was found. + */ +DART_EXPORT Dart_Handle +Dart_GetNativeResolver(Dart_Handle library, Dart_NativeEntryResolver* resolver); + +/** + * Returns the callback used to resolve native function symbols for a library. + * + * \param library A library. + * \param resolver a pointer to a Dart_NativeEntrySymbol. + * + * \return A valid handle if the library was found. + */ +DART_EXPORT Dart_Handle Dart_GetNativeSymbol(Dart_Handle library, + Dart_NativeEntrySymbol* resolver); + +/** + * Sets the callback used to resolve FFI native functions for a library. + * The resolved functions are expected to be a C function pointer of the + * correct signature (as specified in the `@FfiNative()` function + * annotation in Dart code). + * + * NOTE: This is an experimental feature and might change in the future. + * + * \param library A library. + * \param resolver A native function resolver. + * + * \return A valid handle if the native resolver was set successfully. + */ +DART_EXPORT Dart_Handle +Dart_SetFfiNativeResolver(Dart_Handle library, Dart_FfiNativeResolver resolver); + +/* + * ===================== + * Scripts and Libraries + * ===================== + */ + +typedef enum { + Dart_kCanonicalizeUrl = 0, + Dart_kImportTag, + Dart_kKernelTag, +} Dart_LibraryTag; + +/** + * The library tag handler is a multi-purpose callback provided by the + * embedder to the Dart VM. The embedder implements the tag handler to + * provide the ability to load Dart scripts and imports. + * + * -- TAGS -- + * + * Dart_kCanonicalizeUrl + * + * This tag indicates that the embedder should canonicalize 'url' with + * respect to 'library'. For most embedders, the + * Dart_DefaultCanonicalizeUrl function is a sufficient implementation + * of this tag. The return value should be a string holding the + * canonicalized url. + * + * Dart_kImportTag + * + * This tag is used to load a library from IsolateMirror.loadUri. The embedder + * should call Dart_LoadLibraryFromKernel to provide the library to the VM. The + * return value should be an error or library (the result from + * Dart_LoadLibraryFromKernel). + * + * Dart_kKernelTag + * + * This tag is used to load the intermediate file (kernel) generated by + * the Dart front end. This tag is typically used when a 'hot-reload' + * of an application is needed and the VM is 'use dart front end' mode. + * The dart front end typically compiles all the scripts, imports and part + * files into one intermediate file hence we don't use the source/import or + * script tags. The return value should be an error or a TypedData containing + * the kernel bytes. + * + */ +typedef Dart_Handle (*Dart_LibraryTagHandler)( + Dart_LibraryTag tag, + Dart_Handle library_or_package_map_url, + Dart_Handle url); + +/** + * Sets library tag handler for the current isolate. This handler is + * used to handle the various tags encountered while loading libraries + * or scripts in the isolate. + * + * \param handler Handler code to be used for handling the various tags + * encountered while loading libraries or scripts in the isolate. + * + * \return If no error occurs, the handler is set for the isolate. + * Otherwise an error handle is returned. + * + * TODO(turnidge): Document. + */ +DART_EXPORT Dart_Handle +Dart_SetLibraryTagHandler(Dart_LibraryTagHandler handler); + +/** + * Handles deferred loading requests. When this handler is invoked, it should + * eventually load the deferred loading unit with the given id and call + * Dart_DeferredLoadComplete or Dart_DeferredLoadCompleteError. It is + * recommended that the loading occur asynchronously, but it is permitted to + * call Dart_DeferredLoadComplete or Dart_DeferredLoadCompleteError before the + * handler returns. + * + * If an error is returned, it will be propagated through + * `prefix.loadLibrary()`. This is useful for synchronous + * implementations, which must propagate any unwind errors from + * Dart_DeferredLoadComplete or Dart_DeferredLoadComplete. Otherwise the handler + * should return a non-error such as `Dart_Null()`. + */ +typedef Dart_Handle (*Dart_DeferredLoadHandler)(intptr_t loading_unit_id); + +/** + * Sets the deferred load handler for the current isolate. This handler is + * used to handle loading deferred imports in an AppJIT or AppAOT program. + */ +DART_EXPORT Dart_Handle +Dart_SetDeferredLoadHandler(Dart_DeferredLoadHandler handler); + +/** + * Notifies the VM that a deferred load completed successfully. This function + * will eventually cause the corresponding `prefix.loadLibrary()` futures to + * complete. + * + * Requires the current isolate to be the same current isolate during the + * invocation of the Dart_DeferredLoadHandler. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle +Dart_DeferredLoadComplete(intptr_t loading_unit_id, + const uint8_t* snapshot_data, + const uint8_t* snapshot_instructions); + +/** + * Notifies the VM that a deferred load failed. This function + * will eventually cause the corresponding `prefix.loadLibrary()` futures to + * complete with an error. + * + * If `transient` is true, future invocations of `prefix.loadLibrary()` will + * trigger new load requests. If false, futures invocation will complete with + * the same error. + * + * Requires the current isolate to be the same current isolate during the + * invocation of the Dart_DeferredLoadHandler. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle +Dart_DeferredLoadCompleteError(intptr_t loading_unit_id, + const char* error_message, + bool transient); + +/** + * Canonicalizes a url with respect to some library. + * + * The url is resolved with respect to the library's url and some url + * normalizations are performed. + * + * This canonicalization function should be sufficient for most + * embedders to implement the Dart_kCanonicalizeUrl tag. + * + * \param base_url The base url relative to which the url is + * being resolved. + * \param url The url being resolved and canonicalized. This + * parameter is a string handle. + * + * \return If no error occurs, a String object is returned. Otherwise + * an error handle is returned. + */ +DART_EXPORT Dart_Handle Dart_DefaultCanonicalizeUrl(Dart_Handle base_url, + Dart_Handle url); + +/** + * Loads the root library for the current isolate. + * + * Requires there to be no current root library. + * + * \param kernel_buffer A buffer which contains a kernel binary (see + * pkg/kernel/binary.md). Must remain valid until isolate group shutdown. + * \param kernel_size Length of the passed in buffer. + * + * \return A handle to the root library, or an error. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle +Dart_LoadScriptFromKernel(const uint8_t* kernel_buffer, intptr_t kernel_size); + +/** + * Gets the library for the root script for the current isolate. + * + * If the root script has not yet been set for the current isolate, + * this function returns Dart_Null(). This function never returns an + * error handle. + * + * \return Returns the root Library for the current isolate or Dart_Null(). + */ +DART_EXPORT Dart_Handle Dart_RootLibrary(void); + +/** + * Sets the root library for the current isolate. + * + * \return Returns an error handle if `library` is not a library handle. + */ +DART_EXPORT Dart_Handle Dart_SetRootLibrary(Dart_Handle library); + +/** + * Lookup or instantiate a legacy type by name and type arguments from a + * Library. + * + * \param library The library containing the class or interface. + * \param class_name The class name for the type. + * \param number_of_type_arguments Number of type arguments. + * For non parametric types the number of type arguments would be 0. + * \param type_arguments Pointer to an array of type arguments. + * For non parametric types a NULL would be passed in for this argument. + * + * \return If no error occurs, the type is returned. + * Otherwise an error handle is returned. + */ +DART_EXPORT Dart_Handle Dart_GetType(Dart_Handle library, + Dart_Handle class_name, + intptr_t number_of_type_arguments, + Dart_Handle* type_arguments); + +/** + * Lookup or instantiate a nullable type by name and type arguments from + * Library. + * + * \param library The library containing the class or interface. + * \param class_name The class name for the type. + * \param number_of_type_arguments Number of type arguments. + * For non parametric types the number of type arguments would be 0. + * \param type_arguments Pointer to an array of type arguments. + * For non parametric types a NULL would be passed in for this argument. + * + * \return If no error occurs, the type is returned. + * Otherwise an error handle is returned. + */ +DART_EXPORT Dart_Handle Dart_GetNullableType(Dart_Handle library, + Dart_Handle class_name, + intptr_t number_of_type_arguments, + Dart_Handle* type_arguments); + +/** + * Lookup or instantiate a non-nullable type by name and type arguments from + * Library. + * + * \param library The library containing the class or interface. + * \param class_name The class name for the type. + * \param number_of_type_arguments Number of type arguments. + * For non parametric types the number of type arguments would be 0. + * \param type_arguments Pointer to an array of type arguments. + * For non parametric types a NULL would be passed in for this argument. + * + * \return If no error occurs, the type is returned. + * Otherwise an error handle is returned. + */ +DART_EXPORT Dart_Handle +Dart_GetNonNullableType(Dart_Handle library, + Dart_Handle class_name, + intptr_t number_of_type_arguments, + Dart_Handle* type_arguments); + +/** + * Creates a nullable version of the provided type. + * + * \param type The type to be converted to a nullable type. + * + * \return If no error occurs, a nullable type is returned. + * Otherwise an error handle is returned. + */ +DART_EXPORT Dart_Handle Dart_TypeToNullableType(Dart_Handle type); + +/** + * Creates a non-nullable version of the provided type. + * + * \param type The type to be converted to a non-nullable type. + * + * \return If no error occurs, a non-nullable type is returned. + * Otherwise an error handle is returned. + */ +DART_EXPORT Dart_Handle Dart_TypeToNonNullableType(Dart_Handle type); + +/** + * A type's nullability. + * + * \param type A Dart type. + * \param result An out parameter containing the result of the check. True if + * the type is of the specified nullability, false otherwise. + * + * \return Returns an error handle if type is not of type Type. + */ +DART_EXPORT Dart_Handle Dart_IsNullableType(Dart_Handle type, bool* result); +DART_EXPORT Dart_Handle Dart_IsNonNullableType(Dart_Handle type, bool* result); +DART_EXPORT Dart_Handle Dart_IsLegacyType(Dart_Handle type, bool* result); + +/** + * Lookup a class or interface by name from a Library. + * + * \param library The library containing the class or interface. + * \param class_name The name of the class or interface. + * + * \return If no error occurs, the class or interface is + * returned. Otherwise an error handle is returned. + */ +DART_EXPORT Dart_Handle Dart_GetClass(Dart_Handle library, + Dart_Handle class_name); +/* TODO(asiva): The above method needs to be removed once all uses + * of it are removed from the embedder code. */ + +/** + * Returns an import path to a Library, such as "file:///test.dart" or + * "dart:core". + */ +DART_EXPORT Dart_Handle Dart_LibraryUrl(Dart_Handle library); + +/** + * Returns a URL from which a Library was loaded. + */ +DART_EXPORT Dart_Handle Dart_LibraryResolvedUrl(Dart_Handle library); + +/** + * \return An array of libraries. + */ +DART_EXPORT Dart_Handle Dart_GetLoadedLibraries(void); + +DART_EXPORT Dart_Handle Dart_LookupLibrary(Dart_Handle url); +/* TODO(turnidge): Consider returning Dart_Null() when the library is + * not found to distinguish that from a true error case. */ + +/** + * Report an loading error for the library. + * + * \param library The library that failed to load. + * \param error The Dart error instance containing the load error. + * + * \return If the VM handles the error, the return value is + * a null handle. If it doesn't handle the error, the error + * object is returned. + */ +DART_EXPORT Dart_Handle Dart_LibraryHandleError(Dart_Handle library, + Dart_Handle error); + +/** + * Called by the embedder to load a partial program. Does not set the root + * library. + * + * \param kernel_buffer A buffer which contains a kernel binary (see + * pkg/kernel/binary.md). Must remain valid until isolate shutdown. + * \param kernel_buffer_size Length of the passed in buffer. + * + * \return A handle to the main library of the compilation unit, or an error. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle +Dart_LoadLibraryFromKernel(const uint8_t* kernel_buffer, + intptr_t kernel_buffer_size); +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle +Dart_LoadLibrary(Dart_Handle kernel_buffer); + +/** + * Indicates that all outstanding load requests have been satisfied. + * This finalizes all the new classes loaded and optionally completes + * deferred library futures. + * + * Requires there to be a current isolate. + * + * \param complete_futures Specify true if all deferred library + * futures should be completed, false otherwise. + * + * \return Success if all classes have been finalized and deferred library + * futures are completed. Otherwise, returns an error. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle +Dart_FinalizeLoading(bool complete_futures); + +/* + * ===== + * Peers + * ===== + */ + +/** + * The peer field is a lazily allocated field intended for storage of + * an uncommonly used values. Most instances types can have a peer + * field allocated. The exceptions are subtypes of Null, num, and + * bool. + */ + +/** + * Returns the value of peer field of 'object' in 'peer'. + * + * \param object An object. + * \param peer An out parameter that returns the value of the peer + * field. + * + * \return Returns an error if 'object' is a subtype of Null, num, or + * bool. + */ +DART_EXPORT Dart_Handle Dart_GetPeer(Dart_Handle object, void** peer); + +/** + * Sets the value of the peer field of 'object' to the value of + * 'peer'. + * + * \param object An object. + * \param peer A value to store in the peer field. + * + * \return Returns an error if 'object' is a subtype of Null, num, or + * bool. + */ +DART_EXPORT Dart_Handle Dart_SetPeer(Dart_Handle object, void* peer); + +/* + * ====== + * Kernel + * ====== + */ + +/** + * Experimental support for Dart to Kernel parser isolate. + * + * TODO(hausner): Document finalized interface. + * + */ + +// TODO(33433): Remove kernel service from the embedding API. + +typedef enum { + Dart_KernelCompilationStatus_Unknown = -1, + Dart_KernelCompilationStatus_Ok = 0, + Dart_KernelCompilationStatus_Error = 1, + Dart_KernelCompilationStatus_Crash = 2, + Dart_KernelCompilationStatus_MsgFailed = 3, +} Dart_KernelCompilationStatus; + +typedef struct { + Dart_KernelCompilationStatus status; + bool null_safety; + char* error; + uint8_t* kernel; + intptr_t kernel_size; +} Dart_KernelCompilationResult; + +typedef enum { + Dart_KernelCompilationVerbosityLevel_Error = 0, + Dart_KernelCompilationVerbosityLevel_Warning, + Dart_KernelCompilationVerbosityLevel_Info, + Dart_KernelCompilationVerbosityLevel_All, +} Dart_KernelCompilationVerbosityLevel; + +DART_EXPORT bool Dart_IsKernelIsolate(Dart_Isolate isolate); +DART_EXPORT bool Dart_KernelIsolateIsRunning(void); +DART_EXPORT Dart_Port Dart_KernelPort(void); + +/** + * Compiles the given `script_uri` to a kernel file. + * + * \param platform_kernel A buffer containing the kernel of the platform (e.g. + * `vm_platform_strong.dill`). The VM does not take ownership of this memory. + * + * \param platform_kernel_size The length of the platform_kernel buffer. + * + * \param snapshot_compile Set to `true` when the compilation is for a snapshot. + * This is used by the frontend to determine if compilation related information + * should be printed to console (e.g., null safety mode). + * + * \param verbosity Specifies the logging behavior of the kernel compilation + * service. + * + * \return Returns the result of the compilation. + * + * On a successful compilation the returned [Dart_KernelCompilationResult] has + * a status of [Dart_KernelCompilationStatus_Ok] and the `kernel`/`kernel_size` + * fields are set. The caller takes ownership of the malloc()ed buffer. + * + * On a failed compilation the `error` might be set describing the reason for + * the failed compilation. The caller takes ownership of the malloc()ed + * error. + * + * Requires there to be a current isolate. + */ +DART_EXPORT Dart_KernelCompilationResult +Dart_CompileToKernel(const char* script_uri, + const uint8_t* platform_kernel, + const intptr_t platform_kernel_size, + bool incremental_compile, + bool snapshot_compile, + const char* package_config, + Dart_KernelCompilationVerbosityLevel verbosity); + +typedef struct { + const char* uri; + const char* source; +} Dart_SourceFile; + +DART_EXPORT Dart_KernelCompilationResult Dart_KernelListDependencies(void); + +/** + * Sets the kernel buffer which will be used to load Dart SDK sources + * dynamically at runtime. + * + * \param platform_kernel A buffer containing kernel which has sources for the + * Dart SDK populated. Note: The VM does not take ownership of this memory. + * + * \param platform_kernel_size The length of the platform_kernel buffer. + */ +DART_EXPORT void Dart_SetDartLibrarySourcesKernel( + const uint8_t* platform_kernel, + const intptr_t platform_kernel_size); + +/** + * Detect the null safety opt-in status. + * + * When running from source, it is based on the opt-in status of `script_uri`. + * When running from a kernel buffer, it is based on the mode used when + * generating `kernel_buffer`. + * When running from an appJIT or AOT snapshot, it is based on the mode used + * when generating `snapshot_data`. + * + * \param script_uri Uri of the script that contains the source code + * + * \param package_config Uri of the package configuration file (either in format + * of .packages or .dart_tool/package_config.json) for the null safety + * detection to resolve package imports against. If this parameter is not + * passed the package resolution of the parent isolate should be used. + * + * \param original_working_directory current working directory when the VM + * process was launched, this is used to correctly resolve the path specified + * for package_config. + * + * \param snapshot_data Buffer containing the snapshot data of the + * isolate or NULL if no snapshot is provided. If provided, the buffers must + * remain valid until the isolate shuts down. + * + * \param snapshot_instructions Buffer containing the snapshot instructions of + * the isolate or NULL if no snapshot is provided. If provided, the buffers + * must remain valid until the isolate shuts down. + * + * \param kernel_buffer A buffer which contains a kernel/DIL program. Must + * remain valid until isolate shutdown. + * + * \param kernel_buffer_size The size of `kernel_buffer`. + * + * \return Returns true if the null safety is opted in by the input being + * run `script_uri`, `snapshot_data` or `kernel_buffer`. + * + */ +DART_EXPORT bool Dart_DetectNullSafety(const char* script_uri, + const char* package_config, + const char* original_working_directory, + const uint8_t* snapshot_data, + const uint8_t* snapshot_instructions, + const uint8_t* kernel_buffer, + intptr_t kernel_buffer_size); + +#define DART_KERNEL_ISOLATE_NAME "kernel-service" + +/* + * ======= + * Service + * ======= + */ + +#define DART_VM_SERVICE_ISOLATE_NAME "vm-service" + +/** + * Returns true if isolate is the service isolate. + * + * \param isolate An isolate + * + * \return Returns true if 'isolate' is the service isolate. + */ +DART_EXPORT bool Dart_IsServiceIsolate(Dart_Isolate isolate); + +/** + * Writes the CPU profile to the timeline as a series of 'instant' events. + * + * Note that this is an expensive operation. + * + * \param main_port The main port of the Isolate whose profile samples to write. + * \param error An optional error, must be free()ed by caller. + * + * \return Returns true if the profile is successfully written and false + * otherwise. + */ +DART_EXPORT bool Dart_WriteProfileToTimeline(Dart_Port main_port, char** error); + +/* + * ============== + * Precompilation + * ============== + */ + +/** + * Compiles all functions reachable from entry points and marks + * the isolate to disallow future compilation. + * + * Entry points should be specified using `@pragma("vm:entry-point")` + * annotation. + * + * \return An error handle if a compilation error or runtime error running const + * constructors was encountered. + */ +DART_EXPORT Dart_Handle Dart_Precompile(void); + +typedef void (*Dart_CreateLoadingUnitCallback)( + void* callback_data, + intptr_t loading_unit_id, + void** write_callback_data, + void** write_debug_callback_data); +typedef void (*Dart_StreamingWriteCallback)(void* callback_data, + const uint8_t* buffer, + intptr_t size); +typedef void (*Dart_StreamingCloseCallback)(void* callback_data); + +DART_EXPORT Dart_Handle Dart_LoadingUnitLibraryUris(intptr_t loading_unit_id); + +// On Darwin systems, 'dlsym' adds an '_' to the beginning of the symbol name. +// Use the '...CSymbol' definitions for resolving through 'dlsym'. The actual +// symbol names in the objects are given by the '...AsmSymbol' definitions. +#if defined(__APPLE__) +#define kSnapshotBuildIdCSymbol "kDartSnapshotBuildId" +#define kVmSnapshotDataCSymbol "kDartVmSnapshotData" +#define kVmSnapshotInstructionsCSymbol "kDartVmSnapshotInstructions" +#define kVmSnapshotBssCSymbol "kDartVmSnapshotBss" +#define kIsolateSnapshotDataCSymbol "kDartIsolateSnapshotData" +#define kIsolateSnapshotInstructionsCSymbol "kDartIsolateSnapshotInstructions" +#define kIsolateSnapshotBssCSymbol "kDartIsolateSnapshotBss" +#else +#define kSnapshotBuildIdCSymbol "_kDartSnapshotBuildId" +#define kVmSnapshotDataCSymbol "_kDartVmSnapshotData" +#define kVmSnapshotInstructionsCSymbol "_kDartVmSnapshotInstructions" +#define kVmSnapshotBssCSymbol "_kDartVmSnapshotBss" +#define kIsolateSnapshotDataCSymbol "_kDartIsolateSnapshotData" +#define kIsolateSnapshotInstructionsCSymbol "_kDartIsolateSnapshotInstructions" +#define kIsolateSnapshotBssCSymbol "_kDartIsolateSnapshotBss" +#endif + +#define kSnapshotBuildIdAsmSymbol "_kDartSnapshotBuildId" +#define kVmSnapshotDataAsmSymbol "_kDartVmSnapshotData" +#define kVmSnapshotInstructionsAsmSymbol "_kDartVmSnapshotInstructions" +#define kVmSnapshotBssAsmSymbol "_kDartVmSnapshotBss" +#define kIsolateSnapshotDataAsmSymbol "_kDartIsolateSnapshotData" +#define kIsolateSnapshotInstructionsAsmSymbol \ + "_kDartIsolateSnapshotInstructions" +#define kIsolateSnapshotBssAsmSymbol "_kDartIsolateSnapshotBss" + +/** + * Creates a precompiled snapshot. + * - A root library must have been loaded. + * - Dart_Precompile must have been called. + * + * Outputs an assembly file defining the symbols listed in the definitions + * above. + * + * The assembly should be compiled as a static or shared library and linked or + * loaded by the embedder. Running this snapshot requires a VM compiled with + * DART_PRECOMPILED_SNAPSHOT. The kDartVmSnapshotData and + * kDartVmSnapshotInstructions should be passed to Dart_Initialize. The + * kDartIsolateSnapshotData and kDartIsolateSnapshotInstructions should be + * passed to Dart_CreateIsolateGroup. + * + * The callback will be invoked one or more times to provide the assembly code. + * + * If stripped is true, then the assembly code will not include DWARF + * debugging sections. + * + * If debug_callback_data is provided, debug_callback_data will be used with + * the callback to provide separate debugging information. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle +Dart_CreateAppAOTSnapshotAsAssembly(Dart_StreamingWriteCallback callback, + void* callback_data, + bool stripped, + void* debug_callback_data); +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle +Dart_CreateAppAOTSnapshotAsAssemblies( + Dart_CreateLoadingUnitCallback next_callback, + void* next_callback_data, + bool stripped, + Dart_StreamingWriteCallback write_callback, + Dart_StreamingCloseCallback close_callback); + +/** + * Creates a precompiled snapshot. + * - A root library must have been loaded. + * - Dart_Precompile must have been called. + * + * Outputs an ELF shared library defining the symbols + * - _kDartVmSnapshotData + * - _kDartVmSnapshotInstructions + * - _kDartIsolateSnapshotData + * - _kDartIsolateSnapshotInstructions + * + * The shared library should be dynamically loaded by the embedder. + * Running this snapshot requires a VM compiled with DART_PRECOMPILED_SNAPSHOT. + * The kDartVmSnapshotData and kDartVmSnapshotInstructions should be passed to + * Dart_Initialize. The kDartIsolateSnapshotData and + * kDartIsolateSnapshotInstructions should be passed to Dart_CreateIsolate. + * + * The callback will be invoked one or more times to provide the binary output. + * + * If stripped is true, then the binary output will not include DWARF + * debugging sections. + * + * If debug_callback_data is provided, debug_callback_data will be used with + * the callback to provide separate debugging information. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle +Dart_CreateAppAOTSnapshotAsElf(Dart_StreamingWriteCallback callback, + void* callback_data, + bool stripped, + void* debug_callback_data); +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle +Dart_CreateAppAOTSnapshotAsElfs(Dart_CreateLoadingUnitCallback next_callback, + void* next_callback_data, + bool stripped, + Dart_StreamingWriteCallback write_callback, + Dart_StreamingCloseCallback close_callback); + +/** + * Like Dart_CreateAppAOTSnapshotAsAssembly, but only includes + * kDartVmSnapshotData and kDartVmSnapshotInstructions. It also does + * not strip DWARF information from the generated assembly or allow for + * separate debug information. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle +Dart_CreateVMAOTSnapshotAsAssembly(Dart_StreamingWriteCallback callback, + void* callback_data); + +/** + * Sorts the class-ids in depth first traversal order of the inheritance + * tree. This is a costly operation, but it can make method dispatch + * more efficient and is done before writing snapshots. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_SortClasses(void); + +/** + * Creates a snapshot that caches compiled code and type feedback for faster + * startup and quicker warmup in a subsequent process. + * + * Outputs a snapshot in two pieces. The pieces should be passed to + * Dart_CreateIsolateGroup in a VM using the same VM snapshot pieces used in the + * current VM. The instructions piece must be loaded with read and execute + * permissions; the data piece may be loaded as read-only. + * + * - Requires the VM to have not been started with --precompilation. + * - Not supported when targeting IA32. + * - The VM writing the snapshot and the VM reading the snapshot must be the + * same version, must be built in the same DEBUG/RELEASE/PRODUCT mode, must + * be targeting the same architecture, and must both be in checked mode or + * both in unchecked mode. + * + * The buffers are scope allocated and are only valid until the next call to + * Dart_ExitScope. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle +Dart_CreateAppJITSnapshotAsBlobs(uint8_t** isolate_snapshot_data_buffer, + intptr_t* isolate_snapshot_data_size, + uint8_t** isolate_snapshot_instructions_buffer, + intptr_t* isolate_snapshot_instructions_size); + +/** + * Like Dart_CreateAppJITSnapshotAsBlobs, but also creates a new VM snapshot. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle +Dart_CreateCoreJITSnapshotAsBlobs( + uint8_t** vm_snapshot_data_buffer, + intptr_t* vm_snapshot_data_size, + uint8_t** vm_snapshot_instructions_buffer, + intptr_t* vm_snapshot_instructions_size, + uint8_t** isolate_snapshot_data_buffer, + intptr_t* isolate_snapshot_data_size, + uint8_t** isolate_snapshot_instructions_buffer, + intptr_t* isolate_snapshot_instructions_size); + +/** + * Get obfuscation map for precompiled code. + * + * Obfuscation map is encoded as a JSON array of pairs (original name, + * obfuscated name). + * + * \return Returns an error handler if the VM was built in a mode that does not + * support obfuscation. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle +Dart_GetObfuscationMap(uint8_t** buffer, intptr_t* buffer_length); + +/** + * Returns whether the VM only supports running from precompiled snapshots and + * not from any other kind of snapshot or from source (that is, the VM was + * compiled with DART_PRECOMPILED_RUNTIME). + */ +DART_EXPORT bool Dart_IsPrecompiledRuntime(void); + +/** + * Print a native stack trace. Used for crash handling. + * + * If context is NULL, prints the current stack trace. Otherwise, context + * should be a CONTEXT* (Windows) or ucontext_t* (POSIX) from a signal handler + * running on the current thread. + */ +DART_EXPORT void Dart_DumpNativeStackTrace(void* context); + +/** + * Indicate that the process is about to abort, and the Dart VM should not + * attempt to cleanup resources. + */ +DART_EXPORT void Dart_PrepareToAbort(void); + +/** + * Callback provided by the embedder that is used by the VM to + * produce footnotes appended to DWARF stack traces. + * + * Whenever VM formats a stack trace as a string it would call this callback + * passing raw program counters for each frame in the stack trace. + * + * Embedder can then return a string which if not-null will be appended to the + * formatted stack trace. + * + * Returned string is expected to be `malloc()` allocated. VM takes ownership + * of the returned string and will `free()` it. + * + * \param addresses raw program counter addresses for each frame + * \param count number of elements in the addresses array + */ +typedef char* (*Dart_DwarfStackTraceFootnoteCallback)(void* addresses[], + intptr_t count); + +/** + * Configure DWARF stack trace footnote callback. + */ +DART_EXPORT void Dart_SetDwarfStackTraceFootnoteCallback( + Dart_DwarfStackTraceFootnoteCallback callback); + +#endif /* INCLUDE_DART_API_H_ */ /* NOLINT */ diff --git a/pkgs/jni/src/include/dart_api_dl.c b/pkgs/jni/src/include/dart_api_dl.c new file mode 100644 index 000000000..c4a68f444 --- /dev/null +++ b/pkgs/jni/src/include/dart_api_dl.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2020, 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. + */ + +#include "dart_api_dl.h" /* NOLINT */ +#include "dart_version.h" /* NOLINT */ +#include "internal/dart_api_dl_impl.h" /* NOLINT */ + +#include + +#define DART_API_DL_DEFINITIONS(name, R, A) name##_Type name##_DL = NULL; + +DART_API_ALL_DL_SYMBOLS(DART_API_DL_DEFINITIONS) + +#undef DART_API_DL_DEFINITIONS + +typedef void* DartApiEntry_function; + +DartApiEntry_function FindFunctionPointer(const DartApiEntry* entries, + const char* name) { + while (entries->name != NULL) { + if (strcmp(entries->name, name) == 0) return entries->function; + entries++; + } + return NULL; +} + +intptr_t Dart_InitializeApiDL(void* data) { + DartApi* dart_api_data = (DartApi*)data; + + if (dart_api_data->major != DART_API_DL_MAJOR_VERSION) { + // If the DartVM we're running on does not have the same version as this + // file was compiled against, refuse to initialize. The symbols are not + // compatible. + return -1; + } + // Minor versions are allowed to be different. + // If the DartVM has a higher minor version, it will provide more symbols + // than we initialize here. + // If the DartVM has a lower minor version, it will not provide all symbols. + // In that case, we leave the missing symbols un-initialized. Those symbols + // should not be used by the Dart and native code. The client is responsible + // for checking the minor version number himself based on which symbols it + // is using. + // (If we would error out on this case, recompiling native code against a + // newer SDK would break all uses on older SDKs, which is too strict.) + + const DartApiEntry* dart_api_function_pointers = dart_api_data->functions; + +#define DART_API_DL_INIT(name, R, A) \ + name##_DL = \ + (name##_Type)(FindFunctionPointer(dart_api_function_pointers, #name)); + DART_API_ALL_DL_SYMBOLS(DART_API_DL_INIT) +#undef DART_API_DL_INIT + + return 0; +} diff --git a/pkgs/jni/src/include/dart_api_dl.h b/pkgs/jni/src/include/dart_api_dl.h new file mode 100644 index 000000000..cce345009 --- /dev/null +++ b/pkgs/jni/src/include/dart_api_dl.h @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2020, 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. + */ + +#ifndef RUNTIME_INCLUDE_DART_API_DL_H_ +#define RUNTIME_INCLUDE_DART_API_DL_H_ + +#include "dart_api.h" /* NOLINT */ +#include "dart_native_api.h" /* NOLINT */ + +/** \mainpage Dynamically Linked Dart API + * + * This exposes a subset of symbols from dart_api.h and dart_native_api.h + * available in every Dart embedder through dynamic linking. + * + * All symbols are postfixed with _DL to indicate that they are dynamically + * linked and to prevent conflicts with the original symbol. + * + * Link `dart_api_dl.c` file into your library and invoke + * `Dart_InitializeApiDL` with `NativeApi.initializeApiDLData`. + */ + +DART_EXPORT intptr_t Dart_InitializeApiDL(void* data); + +// ============================================================================ +// IMPORTANT! Never update these signatures without properly updating +// DART_API_DL_MAJOR_VERSION and DART_API_DL_MINOR_VERSION. +// +// Verbatim copy of `dart_native_api.h` and `dart_api.h` symbol names and types +// to trigger compile-time errors if the symbols in those files are updated +// without updating these. +// +// Function return and argument types, and typedefs are carbon copied. Structs +// are typechecked nominally in C/C++, so they are not copied, instead a +// comment is added to their definition. +typedef int64_t Dart_Port_DL; + +typedef void (*Dart_NativeMessageHandler_DL)(Dart_Port_DL dest_port_id, + Dart_CObject* message); + +// dart_native_api.h symbols can be called on any thread. +#define DART_NATIVE_API_DL_SYMBOLS(F) \ + /***** dart_native_api.h *****/ \ + /* Dart_Port */ \ + F(Dart_PostCObject, bool, (Dart_Port_DL port_id, Dart_CObject * message)) \ + F(Dart_PostInteger, bool, (Dart_Port_DL port_id, int64_t message)) \ + F(Dart_NewNativePort, Dart_Port_DL, \ + (const char* name, Dart_NativeMessageHandler_DL handler, \ + bool handle_concurrently)) \ + F(Dart_CloseNativePort, bool, (Dart_Port_DL native_port_id)) + +// dart_api.h symbols can only be called on Dart threads. +#define DART_API_DL_SYMBOLS(F) \ + /***** dart_api.h *****/ \ + /* Errors */ \ + F(Dart_IsError, bool, (Dart_Handle handle)) \ + F(Dart_IsApiError, bool, (Dart_Handle handle)) \ + F(Dart_IsUnhandledExceptionError, bool, (Dart_Handle handle)) \ + F(Dart_IsCompilationError, bool, (Dart_Handle handle)) \ + F(Dart_IsFatalError, bool, (Dart_Handle handle)) \ + F(Dart_GetError, const char*, (Dart_Handle handle)) \ + F(Dart_ErrorHasException, bool, (Dart_Handle handle)) \ + F(Dart_ErrorGetException, Dart_Handle, (Dart_Handle handle)) \ + F(Dart_ErrorGetStackTrace, Dart_Handle, (Dart_Handle handle)) \ + F(Dart_NewApiError, Dart_Handle, (const char* error)) \ + F(Dart_NewCompilationError, Dart_Handle, (const char* error)) \ + F(Dart_NewUnhandledExceptionError, Dart_Handle, (Dart_Handle exception)) \ + F(Dart_PropagateError, void, (Dart_Handle handle)) \ + /* Dart_Handle, Dart_PersistentHandle, Dart_WeakPersistentHandle */ \ + F(Dart_HandleFromPersistent, Dart_Handle, (Dart_PersistentHandle object)) \ + F(Dart_HandleFromWeakPersistent, Dart_Handle, \ + (Dart_WeakPersistentHandle object)) \ + F(Dart_NewPersistentHandle, Dart_PersistentHandle, (Dart_Handle object)) \ + F(Dart_SetPersistentHandle, void, \ + (Dart_PersistentHandle obj1, Dart_Handle obj2)) \ + F(Dart_DeletePersistentHandle, void, (Dart_PersistentHandle object)) \ + F(Dart_NewWeakPersistentHandle, Dart_WeakPersistentHandle, \ + (Dart_Handle object, void* peer, intptr_t external_allocation_size, \ + Dart_HandleFinalizer callback)) \ + F(Dart_DeleteWeakPersistentHandle, void, (Dart_WeakPersistentHandle object)) \ + F(Dart_UpdateExternalSize, void, \ + (Dart_WeakPersistentHandle object, intptr_t external_allocation_size)) \ + F(Dart_NewFinalizableHandle, Dart_FinalizableHandle, \ + (Dart_Handle object, void* peer, intptr_t external_allocation_size, \ + Dart_HandleFinalizer callback)) \ + F(Dart_DeleteFinalizableHandle, void, \ + (Dart_FinalizableHandle object, Dart_Handle strong_ref_to_object)) \ + F(Dart_UpdateFinalizableExternalSize, void, \ + (Dart_FinalizableHandle object, Dart_Handle strong_ref_to_object, \ + intptr_t external_allocation_size)) \ + /* Isolates */ \ + F(Dart_CurrentIsolate, Dart_Isolate, (void)) \ + F(Dart_ExitIsolate, void, (void)) \ + F(Dart_EnterIsolate, void, (Dart_Isolate)) \ + /* Dart_Port */ \ + F(Dart_Post, bool, (Dart_Port_DL port_id, Dart_Handle object)) \ + F(Dart_NewSendPort, Dart_Handle, (Dart_Port_DL port_id)) \ + F(Dart_SendPortGetId, Dart_Handle, \ + (Dart_Handle port, Dart_Port_DL * port_id)) \ + /* Scopes */ \ + F(Dart_EnterScope, void, (void)) \ + F(Dart_ExitScope, void, (void)) \ + /* Objects */ \ + F(Dart_IsNull, bool, (Dart_Handle)) + +#define DART_API_ALL_DL_SYMBOLS(F) \ + DART_NATIVE_API_DL_SYMBOLS(F) \ + DART_API_DL_SYMBOLS(F) +// IMPORTANT! Never update these signatures without properly updating +// DART_API_DL_MAJOR_VERSION and DART_API_DL_MINOR_VERSION. +// +// End of verbatim copy. +// ============================================================================ + +// Copy of definition of DART_EXPORT without 'used' attribute. +// +// The 'used' attribute cannot be used with DART_API_ALL_DL_SYMBOLS because +// they are not function declarations, but variable declarations with a +// function pointer type. +// +// The function pointer variables are initialized with the addresses of the +// functions in the VM. If we were to use function declarations instead, we +// would need to forward the call to the VM adding indirection. +#if defined(__CYGWIN__) +#error Tool chain and platform not supported. +#elif defined(_WIN32) +#if defined(DART_SHARED_LIB) +#define DART_EXPORT_DL DART_EXTERN_C __declspec(dllexport) +#else +#define DART_EXPORT_DL DART_EXTERN_C +#endif +#else +#if __GNUC__ >= 4 +#if defined(DART_SHARED_LIB) +#define DART_EXPORT_DL DART_EXTERN_C __attribute__((visibility("default"))) +#else +#define DART_EXPORT_DL DART_EXTERN_C +#endif +#else +#error Tool chain not supported. +#endif +#endif + +#define DART_API_DL_DECLARATIONS(name, R, A) \ + typedef R(*name##_Type) A; \ + DART_EXPORT_DL name##_Type name##_DL; + +DART_API_ALL_DL_SYMBOLS(DART_API_DL_DECLARATIONS) + +#undef DART_API_DL_DECLARATIONS + +#undef DART_EXPORT_DL + +#endif /* RUNTIME_INCLUDE_DART_API_DL_H_ */ /* NOLINT */ diff --git a/pkgs/jni/src/include/dart_embedder_api.h b/pkgs/jni/src/include/dart_embedder_api.h new file mode 100644 index 000000000..e565ebf6e --- /dev/null +++ b/pkgs/jni/src/include/dart_embedder_api.h @@ -0,0 +1,108 @@ +// Copyright (c) 2018, 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. + +#ifndef RUNTIME_INCLUDE_DART_EMBEDDER_API_H_ +#define RUNTIME_INCLUDE_DART_EMBEDDER_API_H_ + +#include "include/dart_api.h" +#include "include/dart_tools_api.h" + +namespace dart { +namespace embedder { + +// Initialize all subsystems of the embedder. +// +// Must be called before the `Dart_Initialize()` call to initialize the +// Dart VM. +// +// Returns true on success and false otherwise, in which case error would +// contain error message. +DART_WARN_UNUSED_RESULT bool InitOnce(char** error); + +// Cleans up all subsystems of the embedder. +// +// Must be called after the `Dart_Cleanup()` call to initialize the +// Dart VM. +void Cleanup(); + +// Common arguments that are passed to isolate creation callback and to +// API methods that create isolates. +struct IsolateCreationData { + // URI for the main script that will be running in the isolate. + const char* script_uri; + + // Advisory name of the main method that will be run by isolate. + // Only used for error messages. + const char* main; + + // Isolate creation flags. Might be absent. + Dart_IsolateFlags* flags; + + // Isolate group callback data. + void* isolate_group_data; + + // Isolate callback data. + void* isolate_data; +}; + +// Create and initialize kernel-service isolate. This method should be used +// when VM invokes isolate creation callback with DART_KERNEL_ISOLATE_NAME as +// script_uri. +// The isolate is created from the given snapshot (might be kernel data or +// app-jit snapshot). +DART_WARN_UNUSED_RESULT Dart_Isolate +CreateKernelServiceIsolate(const IsolateCreationData& data, + const uint8_t* buffer, + intptr_t buffer_size, + char** error); + +// Service isolate configuration. +struct VmServiceConfiguration { + enum { + kBindHttpServerToAFreePort = 0, + kDoNotAutoStartHttpServer = -1 + }; + + // Address to which HTTP server will be bound. + const char* ip; + + // Default port. See enum above for special values. + int port; + + // If non-null, connection information for the VM service will be output to a + // file in JSON format at the location specified. + const char* write_service_info_filename; + + // TODO(vegorov) document these ones. + bool dev_mode; + bool deterministic; + bool disable_auth_codes; +}; + +// Create and initialize vm-service isolate from the given AOT snapshot, which +// is expected to contain all necessary 'vm-service' libraries. +// This method should be used when VM invokes isolate creation callback with +// DART_VM_SERVICE_ISOLATE_NAME as script_uri. +DART_WARN_UNUSED_RESULT Dart_Isolate +CreateVmServiceIsolate(const IsolateCreationData& data, + const VmServiceConfiguration& config, + const uint8_t* isolate_data, + const uint8_t* isolate_instr, + char** error); + +// Create and initialize vm-service isolate from the given kernel binary, which +// is expected to contain all necessary 'vm-service' libraries. +// This method should be used when VM invokes isolate creation callback with +// DART_VM_SERVICE_ISOLATE_NAME as script_uri. +DART_WARN_UNUSED_RESULT Dart_Isolate +CreateVmServiceIsolateFromKernel(const IsolateCreationData& data, + const VmServiceConfiguration& config, + const uint8_t* kernel_buffer, + intptr_t kernel_buffer_size, + char** error); + +} // namespace embedder +} // namespace dart + +#endif // RUNTIME_INCLUDE_DART_EMBEDDER_API_H_ diff --git a/pkgs/jni/src/include/dart_native_api.h b/pkgs/jni/src/include/dart_native_api.h new file mode 100644 index 000000000..79194e03b --- /dev/null +++ b/pkgs/jni/src/include/dart_native_api.h @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2013, 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. + */ + +#ifndef RUNTIME_INCLUDE_DART_NATIVE_API_H_ +#define RUNTIME_INCLUDE_DART_NATIVE_API_H_ + +#include "dart_api.h" /* NOLINT */ + +/* + * ========================================== + * Message sending/receiving from native code + * ========================================== + */ + +/** + * A Dart_CObject is used for representing Dart objects as native C + * data outside the Dart heap. These objects are totally detached from + * the Dart heap. Only a subset of the Dart objects have a + * representation as a Dart_CObject. + * + * The string encoding in the 'value.as_string' is UTF-8. + * + * All the different types from dart:typed_data are exposed as type + * kTypedData. The specific type from dart:typed_data is in the type + * field of the as_typed_data structure. The length in the + * as_typed_data structure is always in bytes. + * + * The data for kTypedData is copied on message send and ownership remains with + * the caller. The ownership of data for kExternalTyped is passed to the VM on + * message send and returned when the VM invokes the + * Dart_HandleFinalizer callback; a non-NULL callback must be provided. + * + * Note that Dart_CObject_kNativePointer is intended for internal use by + * dart:io implementation and has no connection to dart:ffi Pointer class. + * It represents a pointer to a native resource of a known type. + * The receiving side will only see this pointer as an integer and will not + * see the specified finalizer. + * The specified finalizer will only be invoked if the message is not delivered. + */ +typedef enum { + Dart_CObject_kNull = 0, + Dart_CObject_kBool, + Dart_CObject_kInt32, + Dart_CObject_kInt64, + Dart_CObject_kDouble, + Dart_CObject_kString, + Dart_CObject_kArray, + Dart_CObject_kTypedData, + Dart_CObject_kExternalTypedData, + Dart_CObject_kSendPort, + Dart_CObject_kCapability, + Dart_CObject_kNativePointer, + Dart_CObject_kUnsupported, + Dart_CObject_kUnmodifiableExternalTypedData, + Dart_CObject_kNumberOfTypes +} Dart_CObject_Type; +// This enum is versioned by DART_API_DL_MAJOR_VERSION, only add at the end +// and bump the DART_API_DL_MINOR_VERSION. + +typedef struct _Dart_CObject { + Dart_CObject_Type type; + union { + bool as_bool; + int32_t as_int32; + int64_t as_int64; + double as_double; + const char* as_string; + struct { + Dart_Port id; + Dart_Port origin_id; + } as_send_port; + struct { + int64_t id; + } as_capability; + struct { + intptr_t length; + struct _Dart_CObject** values; + } as_array; + struct { + Dart_TypedData_Type type; + intptr_t length; /* in elements, not bytes */ + const uint8_t* values; + } as_typed_data; + struct { + Dart_TypedData_Type type; + intptr_t length; /* in elements, not bytes */ + uint8_t* data; + void* peer; + Dart_HandleFinalizer callback; + } as_external_typed_data; + struct { + intptr_t ptr; + intptr_t size; + Dart_HandleFinalizer callback; + } as_native_pointer; + } value; +} Dart_CObject; +// This struct is versioned by DART_API_DL_MAJOR_VERSION, bump the version when +// changing this struct. + +/** + * Posts a message on some port. The message will contain the Dart_CObject + * object graph rooted in 'message'. + * + * While the message is being sent the state of the graph of Dart_CObject + * structures rooted in 'message' should not be accessed, as the message + * generation will make temporary modifications to the data. When the message + * has been sent the graph will be fully restored. + * + * If true is returned, the message was enqueued, and finalizers for external + * typed data will eventually run, even if the receiving isolate shuts down + * before processing the message. If false is returned, the message was not + * enqueued and ownership of external typed data in the message remains with the + * caller. + * + * This function may be called on any thread when the VM is running (that is, + * after Dart_Initialize has returned and before Dart_Cleanup has been called). + * + * \param port_id The destination port. + * \param message The message to send. + * + * \return True if the message was posted. + */ +DART_EXPORT bool Dart_PostCObject(Dart_Port port_id, Dart_CObject* message); + +/** + * Posts a message on some port. The message will contain the integer 'message'. + * + * \param port_id The destination port. + * \param message The message to send. + * + * \return True if the message was posted. + */ +DART_EXPORT bool Dart_PostInteger(Dart_Port port_id, int64_t message); + +/** + * A native message handler. + * + * This handler is associated with a native port by calling + * Dart_NewNativePort. + * + * The message received is decoded into the message structure. The + * lifetime of the message data is controlled by the caller. All the + * data references from the message are allocated by the caller and + * will be reclaimed when returning to it. + */ +typedef void (*Dart_NativeMessageHandler)(Dart_Port dest_port_id, + Dart_CObject* message); + +/** + * Creates a new native port. When messages are received on this + * native port, then they will be dispatched to the provided native + * message handler. + * + * \param name The name of this port in debugging messages. + * \param handler The C handler to run when messages arrive on the port. + * \param handle_concurrently Is it okay to process requests on this + * native port concurrently? + * + * \return If successful, returns the port id for the native port. In + * case of error, returns ILLEGAL_PORT. + */ +DART_EXPORT Dart_Port Dart_NewNativePort(const char* name, + Dart_NativeMessageHandler handler, + bool handle_concurrently); +/* TODO(turnidge): Currently handle_concurrently is ignored. */ + +/** + * Closes the native port with the given id. + * + * The port must have been allocated by a call to Dart_NewNativePort. + * + * \param native_port_id The id of the native port to close. + * + * \return Returns true if the port was closed successfully. + */ +DART_EXPORT bool Dart_CloseNativePort(Dart_Port native_port_id); + +/* + * ================== + * Verification Tools + * ================== + */ + +/** + * Forces all loaded classes and functions to be compiled eagerly in + * the current isolate.. + * + * TODO(turnidge): Document. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_CompileAll(void); + +/** + * Finalizes all classes. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_FinalizeAllClasses(void); + +/* This function is intentionally undocumented. + * + * It should not be used outside internal tests. + */ +DART_EXPORT void* Dart_ExecuteInternalCommand(const char* command, void* arg); + +#endif /* INCLUDE_DART_NATIVE_API_H_ */ /* NOLINT */ diff --git a/pkgs/jni/src/include/dart_tools_api.h b/pkgs/jni/src/include/dart_tools_api.h new file mode 100644 index 000000000..7b706bc97 --- /dev/null +++ b/pkgs/jni/src/include/dart_tools_api.h @@ -0,0 +1,658 @@ +// Copyright (c) 2011, 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. + +#ifndef RUNTIME_INCLUDE_DART_TOOLS_API_H_ +#define RUNTIME_INCLUDE_DART_TOOLS_API_H_ + +#include "dart_api.h" /* NOLINT */ + +/** \mainpage Dart Tools Embedding API Reference + * + * This reference describes the Dart embedding API for tools. Tools include + * a debugger, service protocol, and timeline. + * + * NOTE: The APIs described in this file are unstable and subject to change. + * + * This reference is generated from the header include/dart_tools_api.h. + */ + +/* + * ======== + * Debugger + * ======== + */ + +/** + * ILLEGAL_ISOLATE_ID is a number guaranteed never to be associated with a + * valid isolate. + */ +#define ILLEGAL_ISOLATE_ID ILLEGAL_PORT + +/** + * ILLEGAL_ISOLATE_GROUP_ID is a number guaranteed never to be associated with a + * valid isolate group. + */ +#define ILLEGAL_ISOLATE_GROUP_ID 0 + +/* + * ======= + * Service + * ======= + */ + +/** + * A service request callback function. + * + * These callbacks, registered by the embedder, are called when the VM receives + * a service request it can't handle and the service request command name + * matches one of the embedder registered handlers. + * + * The return value of the callback indicates whether the response + * should be used as a regular result or an error result. + * Specifically, if the callback returns true, a regular JSON-RPC + * response is built in the following way: + * + * { + * "jsonrpc": "2.0", + * "result": , + * "id": , + * } + * + * If the callback returns false, a JSON-RPC error is built like this: + * + * { + * "jsonrpc": "2.0", + * "error": , + * "id": , + * } + * + * \param method The rpc method name. + * \param param_keys Service requests can have key-value pair parameters. The + * keys and values are flattened and stored in arrays. + * \param param_values The values associated with the keys. + * \param num_params The length of the param_keys and param_values arrays. + * \param user_data The user_data pointer registered with this handler. + * \param result A C string containing a valid JSON object. The returned + * pointer will be freed by the VM by calling free. + * + * \return True if the result is a regular JSON-RPC response, false if the + * result is a JSON-RPC error. + */ +typedef bool (*Dart_ServiceRequestCallback)(const char* method, + const char** param_keys, + const char** param_values, + intptr_t num_params, + void* user_data, + const char** json_object); + +/** + * Register a Dart_ServiceRequestCallback to be called to handle + * requests for the named rpc on a specific isolate. The callback will + * be invoked with the current isolate set to the request target. + * + * \param method The name of the method that this callback is responsible for. + * \param callback The callback to invoke. + * \param user_data The user data passed to the callback. + * + * NOTE: If multiple callbacks with the same name are registered, only + * the last callback registered will be remembered. + */ +DART_EXPORT void Dart_RegisterIsolateServiceRequestCallback( + const char* method, + Dart_ServiceRequestCallback callback, + void* user_data); + +/** + * Register a Dart_ServiceRequestCallback to be called to handle + * requests for the named rpc. The callback will be invoked without a + * current isolate. + * + * \param method The name of the command that this callback is responsible for. + * \param callback The callback to invoke. + * \param user_data The user data passed to the callback. + * + * NOTE: If multiple callbacks with the same name are registered, only + * the last callback registered will be remembered. + */ +DART_EXPORT void Dart_RegisterRootServiceRequestCallback( + const char* method, + Dart_ServiceRequestCallback callback, + void* user_data); + +/** + * Embedder information which can be requested by the VM for internal or + * reporting purposes. + * + * The pointers in this structure are not going to be cached or freed by the VM. + */ + + #define DART_EMBEDDER_INFORMATION_CURRENT_VERSION (0x00000001) + +typedef struct { + int32_t version; + const char* name; // [optional] The name of the embedder + int64_t current_rss; // [optional] the current RSS of the embedder + int64_t max_rss; // [optional] the maximum RSS of the embedder +} Dart_EmbedderInformation; + +/** + * Callback provided by the embedder that is used by the VM to request + * information. + * + * \return Returns a pointer to a Dart_EmbedderInformation structure. + * The embedder keeps the ownership of the structure and any field in it. + * The embedder must ensure that the structure will remain valid until the + * next invocation of the callback. + */ +typedef void (*Dart_EmbedderInformationCallback)( + Dart_EmbedderInformation* info); + +/** + * Register a Dart_ServiceRequestCallback to be called to handle + * requests for the named rpc. The callback will be invoked without a + * current isolate. + * + * \param method The name of the command that this callback is responsible for. + * \param callback The callback to invoke. + * \param user_data The user data passed to the callback. + * + * NOTE: If multiple callbacks are registered, only the last callback registered + * will be remembered. + */ +DART_EXPORT void Dart_SetEmbedderInformationCallback( + Dart_EmbedderInformationCallback callback); + +/** + * Invoke a vm-service method and wait for its result. + * + * \param request_json The utf8-encoded json-rpc request. + * \param request_json_length The length of the json-rpc request. + * + * \param response_json The returned utf8-encoded json response, must be + * free()ed by caller. + * \param response_json_length The length of the returned json response. + * \param error An optional error, must be free()ed by caller. + * + * \return Whether the call was successfully performed. + * + * NOTE: This method does not need a current isolate and must not have the + * vm-isolate being the current isolate. It must be called after + * Dart_Initialize() and before Dart_Cleanup(). + */ +DART_EXPORT bool Dart_InvokeVMServiceMethod(uint8_t* request_json, + intptr_t request_json_length, + uint8_t** response_json, + intptr_t* response_json_length, + char** error); + +/* + * ======== + * Event Streams + * ======== + */ + +/** + * A callback invoked when the VM service gets a request to listen to + * some stream. + * + * \return Returns true iff the embedder supports the named stream id. + */ +typedef bool (*Dart_ServiceStreamListenCallback)(const char* stream_id); + +/** + * A callback invoked when the VM service gets a request to cancel + * some stream. + */ +typedef void (*Dart_ServiceStreamCancelCallback)(const char* stream_id); + +/** + * Adds VM service stream callbacks. + * + * \param listen_callback A function pointer to a listen callback function. + * A listen callback function should not be already set when this function + * is called. A NULL value removes the existing listen callback function + * if any. + * + * \param cancel_callback A function pointer to a cancel callback function. + * A cancel callback function should not be already set when this function + * is called. A NULL value removes the existing cancel callback function + * if any. + * + * \return Success if the callbacks were added. Otherwise, returns an + * error handle. + */ +DART_EXPORT char* Dart_SetServiceStreamCallbacks( + Dart_ServiceStreamListenCallback listen_callback, + Dart_ServiceStreamCancelCallback cancel_callback); + +/** + * Sends a data event to clients of the VM Service. + * + * A data event is used to pass an array of bytes to subscribed VM + * Service clients. For example, in the standalone embedder, this is + * function used to provide WriteEvents on the Stdout and Stderr + * streams. + * + * If the embedder passes in a stream id for which no client is + * subscribed, then the event is ignored. + * + * \param stream_id The id of the stream on which to post the event. + * + * \param event_kind A string identifying what kind of event this is. + * For example, 'WriteEvent'. + * + * \param bytes A pointer to an array of bytes. + * + * \param bytes_length The length of the byte array. + * + * \return NULL if the arguments are well formed. Otherwise, returns an + * error string. The caller is responsible for freeing the error message. + */ +DART_EXPORT char* Dart_ServiceSendDataEvent(const char* stream_id, + const char* event_kind, + const uint8_t* bytes, + intptr_t bytes_length); + +/* + * ======== + * Reload support + * ======== + * + * These functions are used to implement reloading in the Dart VM. + * This is an experimental feature, so embedders should be prepared + * for these functions to change. + */ + +/** + * A callback which determines whether the file at some url has been + * modified since some time. If the file cannot be found, true should + * be returned. + */ +typedef bool (*Dart_FileModifiedCallback)(const char* url, int64_t since); + +DART_EXPORT char* Dart_SetFileModifiedCallback( + Dart_FileModifiedCallback file_modified_callback); + +/** + * Returns true if isolate is currently reloading. + */ +DART_EXPORT bool Dart_IsReloading(); + +/* + * ======== + * Timeline + * ======== + */ + +/** + * Enable tracking of specified timeline category. This is operational + * only when systrace timeline functionality is turned on. + * + * \param categories A comma separated list of categories that need to + * be enabled, the categories are + * "all" : All categories + * "API" - Execution of Dart C API functions + * "Compiler" - Execution of Dart JIT compiler + * "CompilerVerbose" - More detailed Execution of Dart JIT compiler + * "Dart" - Execution of Dart code + * "Debugger" - Execution of Dart debugger + * "Embedder" - Execution of Dart embedder code + * "GC" - Execution of Dart Garbage Collector + * "Isolate" - Dart Isolate lifecycle execution + * "VM" - Execution in Dart VM runtime code + * "" - None + * + * When "all" is specified all the categories are enabled. + * When a comma separated list of categories is specified, the categories + * that are specified will be enabled and the rest will be disabled. + * When "" is specified all the categories are disabled. + * The category names are case sensitive. + * eg: Dart_EnableTimelineCategory("all"); + * Dart_EnableTimelineCategory("GC,API,Isolate"); + * Dart_EnableTimelineCategory("GC,Debugger,Dart"); + * + * \return True if the categories were successfully enabled, False otherwise. + */ +DART_EXPORT bool Dart_SetEnabledTimelineCategory(const char* categories); + +/** + * Returns a timestamp in microseconds. This timestamp is suitable for + * passing into the timeline system, and uses the same monotonic clock + * as dart:developer's Timeline.now. + * + * \return A timestamp that can be passed to the timeline system. + */ +DART_EXPORT int64_t Dart_TimelineGetMicros(); + +/** + * Returns a raw timestamp in from the monotonic clock. + * + * \return A raw timestamp from the monotonic clock. + */ +DART_EXPORT int64_t Dart_TimelineGetTicks(); + +/** + * Returns the frequency of the monotonic clock. + * + * \return The frequency of the monotonic clock. + */ +DART_EXPORT int64_t Dart_TimelineGetTicksFrequency(); + +typedef enum { + Dart_Timeline_Event_Begin, // Phase = 'B'. + Dart_Timeline_Event_End, // Phase = 'E'. + Dart_Timeline_Event_Instant, // Phase = 'i'. + Dart_Timeline_Event_Duration, // Phase = 'X'. + Dart_Timeline_Event_Async_Begin, // Phase = 'b'. + Dart_Timeline_Event_Async_End, // Phase = 'e'. + Dart_Timeline_Event_Async_Instant, // Phase = 'n'. + Dart_Timeline_Event_Counter, // Phase = 'C'. + Dart_Timeline_Event_Flow_Begin, // Phase = 's'. + Dart_Timeline_Event_Flow_Step, // Phase = 't'. + Dart_Timeline_Event_Flow_End, // Phase = 'f'. +} Dart_Timeline_Event_Type; + +/** + * Add a timeline event to the embedder stream. + * + * DEPRECATED: this function will be removed in Dart SDK v3.2. + * + * \param label The name of the event. Its lifetime must extend at least until + * Dart_Cleanup. + * \param timestamp0 The first timestamp of the event. + * \param timestamp1_or_id When reporting an event of type + * |Dart_Timeline_Event_Duration|, the second (end) timestamp of the event + * should be passed through |timestamp1_or_id|. When reporting an event of + * type |Dart_Timeline_Event_Async_Begin|, |Dart_Timeline_Event_Async_End|, + * or |Dart_Timeline_Event_Async_Instant|, the async ID associated with the + * event should be passed through |timestamp1_or_id|. When reporting an + * event of type |Dart_Timeline_Event_Flow_Begin|, + * |Dart_Timeline_Event_Flow_Step|, or |Dart_Timeline_Event_Flow_End|, the + * flow ID associated with the event should be passed through + * |timestamp1_or_id|. When reporting an event of type + * |Dart_Timeline_Event_Begin| or |Dart_Timeline_Event_End|, the event ID + * associated with the event should be passed through |timestamp1_or_id|. + * Note that this event ID will only be used by the MacOS recorder. The + * argument to |timestamp1_or_id| will not be used when reporting events of + * other types. + * \param argument_count The number of argument names and values. + * \param argument_names An array of names of the arguments. The lifetime of the + * names must extend at least until Dart_Cleanup. The array may be reclaimed + * when this call returns. + * \param argument_values An array of values of the arguments. The values and + * the array may be reclaimed when this call returns. + */ +DART_EXPORT void Dart_TimelineEvent(const char* label, + int64_t timestamp0, + int64_t timestamp1_or_id, + Dart_Timeline_Event_Type type, + intptr_t argument_count, + const char** argument_names, + const char** argument_values); + +/** + * Add a timeline event to the embedder stream. + * + * Note regarding flow events: events must be associated with flow IDs in two + * different ways to allow flow events to be serialized correctly in both + * Chrome's JSON trace event format and Perfetto's proto trace format. Events + * of type |Dart_Timeline_Event_Flow_Begin|, |Dart_Timeline_Event_Flow_Step|, + * and |Dart_Timeline_Event_Flow_End| must be reported to support serialization + * in Chrome's trace format. The |flow_ids| argument must be supplied when + * reporting events of type |Dart_Timeline_Event_Begin|, + * |Dart_Timeline_Event_Duration|, |Dart_Timeline_Event_Instant|, + * |Dart_Timeline_Event_Async_Begin|, and |Dart_Timeline_Event_Async_Instant| to + * support serialization in Perfetto's proto format. + * + * \param label The name of the event. Its lifetime must extend at least until + * Dart_Cleanup. + * \param timestamp0 The first timestamp of the event. + * \param timestamp1_or_id When reporting an event of type + * |Dart_Timeline_Event_Duration|, the second (end) timestamp of the event + * should be passed through |timestamp1_or_id|. When reporting an event of + * type |Dart_Timeline_Event_Async_Begin|, |Dart_Timeline_Event_Async_End|, + * or |Dart_Timeline_Event_Async_Instant|, the async ID associated with the + * event should be passed through |timestamp1_or_id|. When reporting an + * event of type |Dart_Timeline_Event_Flow_Begin|, + * |Dart_Timeline_Event_Flow_Step|, or |Dart_Timeline_Event_Flow_End|, the + * flow ID associated with the event should be passed through + * |timestamp1_or_id|. When reporting an event of type + * |Dart_Timeline_Event_Begin| or |Dart_Timeline_Event_End|, the event ID + * associated with the event should be passed through |timestamp1_or_id|. + * Note that this event ID will only be used by the MacOS recorder. The + * argument to |timestamp1_or_id| will not be used when reporting events of + * other types. + * \param flow_id_count The number of flow IDs associated with this event. + * \param flow_ids An array of flow IDs associated with this event. The array + * may be reclaimed when this call returns. + * \param argument_count The number of argument names and values. + * \param argument_names An array of names of the arguments. The lifetime of the + * names must extend at least until Dart_Cleanup. The array may be reclaimed + * when this call returns. + * \param argument_values An array of values of the arguments. The values and + * the array may be reclaimed when this call returns. + */ +DART_EXPORT void Dart_RecordTimelineEvent(const char* label, + int64_t timestamp0, + int64_t timestamp1_or_id, + intptr_t flow_id_count, + const int64_t* flow_ids, + Dart_Timeline_Event_Type type, + intptr_t argument_count, + const char** argument_names, + const char** argument_values); + +/** + * Associates a name with the current thread. This name will be used to name + * threads in the timeline. Can only be called after a call to Dart_Initialize. + * + * \param name The name of the thread. + */ +DART_EXPORT void Dart_SetThreadName(const char* name); + +typedef struct { + const char* name; + const char* value; +} Dart_TimelineRecorderEvent_Argument; + +#define DART_TIMELINE_RECORDER_CURRENT_VERSION (0x00000002) + +typedef struct { + /* Set to DART_TIMELINE_RECORDER_CURRENT_VERSION */ + int32_t version; + + /* The event's type / phase. */ + Dart_Timeline_Event_Type type; + + /* The event's timestamp according to the same clock as + * Dart_TimelineGetMicros. For a duration event, this is the beginning time. + */ + int64_t timestamp0; + + /** + * For a duration event, this is the end time. For an async event, this is the + * async ID. For a flow event, this is the flow ID. For a begin or end event, + * this is the event ID (which is only referenced by the MacOS recorder). + */ + int64_t timestamp1_or_id; + + /* The current isolate of the event, as if by Dart_GetMainPortId, or + * ILLEGAL_PORT if the event had no current isolate. */ + Dart_Port isolate; + + /* The current isolate group of the event, as if by + * Dart_CurrentIsolateGroupId, or ILLEGAL_PORT if the event had no current + * isolate group. */ + Dart_IsolateGroupId isolate_group; + + /* The callback data associated with the isolate if any. */ + void* isolate_data; + + /* The callback data associated with the isolate group if any. */ + void* isolate_group_data; + + /* The name / label of the event. */ + const char* label; + + /* The stream / category of the event. */ + const char* stream; + + intptr_t argument_count; + Dart_TimelineRecorderEvent_Argument* arguments; +} Dart_TimelineRecorderEvent; + +/** + * Callback provided by the embedder to handle the completion of timeline + * events. + * + * \param event A timeline event that has just been completed. The VM keeps + * ownership of the event and any field in it (i.e., the embedder should copy + * any values it needs after the callback returns). + */ +typedef void (*Dart_TimelineRecorderCallback)( + Dart_TimelineRecorderEvent* event); + +/** + * Register a `Dart_TimelineRecorderCallback` to be called as timeline events + * are completed. + * + * The callback will be invoked without a current isolate. + * + * The callback will be invoked on the thread completing the event. Because + * `Dart_TimelineEvent` may be called by any thread, the callback may be called + * on any thread. + * + * The callback may be invoked at any time after `Dart_Initialize` is called and + * before `Dart_Cleanup` returns. + * + * If multiple callbacks are registered, only the last callback registered + * will be remembered. Providing a NULL callback will clear the registration + * (i.e., a NULL callback produced a no-op instead of a crash). + * + * Setting a callback is insufficient to receive events through the callback. The + * VM flag `timeline_recorder` must also be set to `callback`. + */ +DART_EXPORT void Dart_SetTimelineRecorderCallback( + Dart_TimelineRecorderCallback callback); + +/* + * ======= + * Metrics + * ======= + */ + +/** + * Return metrics gathered for the VM and individual isolates. + */ +DART_EXPORT int64_t +Dart_IsolateGroupHeapOldUsedMetric(Dart_IsolateGroup group); // Byte +DART_EXPORT int64_t +Dart_IsolateGroupHeapOldCapacityMetric(Dart_IsolateGroup group); // Byte +DART_EXPORT int64_t +Dart_IsolateGroupHeapOldExternalMetric(Dart_IsolateGroup group); // Byte +DART_EXPORT int64_t +Dart_IsolateGroupHeapNewUsedMetric(Dart_IsolateGroup group); // Byte +DART_EXPORT int64_t +Dart_IsolateGroupHeapNewCapacityMetric(Dart_IsolateGroup group); // Byte +DART_EXPORT int64_t +Dart_IsolateGroupHeapNewExternalMetric(Dart_IsolateGroup group); // Byte + +/* + * ======== + * UserTags + * ======== + */ + +/* + * Gets the current isolate's currently set UserTag instance. + * + * \return The currently set UserTag instance. + */ +DART_EXPORT Dart_Handle Dart_GetCurrentUserTag(); + +/* + * Gets the current isolate's default UserTag instance. + * + * \return The default UserTag with label 'Default' + */ +DART_EXPORT Dart_Handle Dart_GetDefaultUserTag(); + +/* + * Creates a new UserTag instance. + * + * \param label The name of the new UserTag. + * + * \return The newly created UserTag instance or an error handle. + */ +DART_EXPORT Dart_Handle Dart_NewUserTag(const char* label); + +/* + * Updates the current isolate's UserTag to a new value. + * + * \param user_tag The UserTag to be set as the current UserTag. + * + * \return The previously set UserTag instance or an error handle. + */ +DART_EXPORT Dart_Handle Dart_SetCurrentUserTag(Dart_Handle user_tag); + +/* + * Returns the label of a given UserTag instance. + * + * \param user_tag The UserTag from which the label will be retrieved. + * + * \return The UserTag's label. NULL if the user_tag is invalid. The caller is + * responsible for freeing the returned label. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT char* Dart_GetUserTagLabel( + Dart_Handle user_tag); + +/* + * ======= + * Heap Snapshot + * ======= + */ + +/** + * Callback provided by the caller of `Dart_WriteHeapSnapshot` which is + * used to write out chunks of the requested heap snapshot. + * + * \param context An opaque context which was passed to `Dart_WriteHeapSnapshot` + * together with this callback. + * + * \param buffer Pointer to the buffer containing a chunk of the snapshot. + * The callback owns the buffer and needs to `free` it. + * + * \param size Number of bytes in the `buffer` to be written. + * + * \param is_last Set to `true` for the last chunk. The callback will not + * be invoked again after it was invoked once with `is_last` set to `true`. + */ +typedef void (*Dart_HeapSnapshotWriteChunkCallback)(void* context, + uint8_t* buffer, + intptr_t size, + bool is_last); + +/** + * Generate heap snapshot of the current isolate group and stream it into the + * given `callback`. VM would produce snapshot in chunks and send these chunks + * one by one back to the embedder by invoking the provided `callback`. + * + * This API enables embedder to stream snapshot into a file or socket without + * allocating a buffer to hold the whole snapshot in memory. + * + * The isolate group will be paused for the duration of this operation. + * + * \param write Callback used to write chunks of the heap snapshot. + * + * \param context Opaque context which would be passed on each invocation of + * `write` callback. + * + * \returns `nullptr` if the operation is successful otherwise error message. + * Caller owns error message string and needs to `free` it. + */ +DART_EXPORT char* Dart_WriteHeapSnapshot( + Dart_HeapSnapshotWriteChunkCallback write, + void* context); + +#endif // RUNTIME_INCLUDE_DART_TOOLS_API_H_ diff --git a/pkgs/jni/src/include/dart_version.h b/pkgs/jni/src/include/dart_version.h new file mode 100644 index 000000000..e2d3651fb --- /dev/null +++ b/pkgs/jni/src/include/dart_version.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2020, 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. + */ + +#ifndef RUNTIME_INCLUDE_DART_VERSION_H_ +#define RUNTIME_INCLUDE_DART_VERSION_H_ + +// On breaking changes the major version is increased. +// On backwards compatible changes the minor version is increased. +// The versioning covers the symbols exposed in dart_api_dl.h +#define DART_API_DL_MAJOR_VERSION 2 +#define DART_API_DL_MINOR_VERSION 3 + +#endif /* RUNTIME_INCLUDE_DART_VERSION_H_ */ /* NOLINT */ diff --git a/pkgs/jni/src/include/internal/dart_api_dl_impl.h b/pkgs/jni/src/include/internal/dart_api_dl_impl.h new file mode 100644 index 000000000..e4a568931 --- /dev/null +++ b/pkgs/jni/src/include/internal/dart_api_dl_impl.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2020, 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. + */ + +#ifndef RUNTIME_INCLUDE_INTERNAL_DART_API_DL_IMPL_H_ +#define RUNTIME_INCLUDE_INTERNAL_DART_API_DL_IMPL_H_ + +typedef struct { + const char* name; + void (*function)(void); +} DartApiEntry; + +typedef struct { + const int major; + const int minor; + const DartApiEntry* const functions; +} DartApi; + +#endif /* RUNTIME_INCLUDE_INTERNAL_DART_API_DL_IMPL_H_ */ /* NOLINT */ diff --git a/pkgs/jni/src/jni_constants.h b/pkgs/jni/src/jni_constants.h new file mode 100644 index 000000000..8423ca10d --- /dev/null +++ b/pkgs/jni/src/jni_constants.h @@ -0,0 +1,31 @@ +// 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. + +// This file re-exports some JNI constants as enum, because they are not +// currently being included when they are in macro form. + +enum JniBooleanValues { JNI_FALSE = 0, JNI_TRUE = 1 }; + +enum JniVersions { + JNI_VERSION_1_1 = 0x00010001, + JNI_VERSION_1_2 = 0x00010002, + JNI_VERSION_1_4 = 0x00010004, + JNI_VERSION_1_6 = 0x00010006, +}; + +enum JniErrorCode { + // Error codes from JNI + JNI_OK = 0, /* no error */ + JNI_ERR = -1, /* generic error */ + JNI_EDETACHED = -2, /* thread detached from the VM */ + JNI_EVERSION = -3, /* JNI version error */ + JNI_ENOMEM = -4, /* Out of memory */ + JNI_EEXIST = -5, /* VM already created */ + JNI_EINVAL = -6, /* Invalid argument */ +}; + +enum JniBufferWriteBack { + JNI_COMMIT = 1, /* copy content, do not free buffer */ + JNI_ABORT = 2, /* free buffer w/o copying back */ +}; diff --git a/pkgs/jni/src/third_party/global_jni_env.c b/pkgs/jni/src/third_party/global_jni_env.c new file mode 100644 index 000000000..7ddc16414 --- /dev/null +++ b/pkgs/jni/src/third_party/global_jni_env.c @@ -0,0 +1,2509 @@ +// Auto generated file. Do not edit. + +// This is generated from JNI header in Android NDK. License for the same is +// provided below. + +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * JNI specification, as defined by Sun: + * http://java.sun.com/javase/6/docs/technotes/guides/jni/spec/jniTOC.html + * + * Everything here is expected to be VM-neutral. + */ + +#include "global_jni_env.h" + +JniResult globalEnv_GetVersion() { + attach_thread(); + jint _result = (*jniEnv)->GetVersion(jniEnv); + return (JniResult){.value = {.i = _result}, .exception = NULL}; +} + +JniClassLookupResult globalEnv_DefineClass(char* name, + jobject loader, + jbyte* buf, + jsize bufLen) { + attach_thread(); + jclass _result = (*jniEnv)->DefineClass(jniEnv, name, loader, buf, bufLen); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniClassLookupResult){.value = NULL, .exception = _exception}; + } + _result = to_global_ref(_result); + return (JniClassLookupResult){.value = _result, .exception = NULL}; +} + +JniClassLookupResult globalEnv_FindClass(char* name) { + attach_thread(); + jclass _result = (*jniEnv)->FindClass(jniEnv, name); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniClassLookupResult){.value = NULL, .exception = _exception}; + } + _result = to_global_ref(_result); + return (JniClassLookupResult){.value = _result, .exception = NULL}; +} + +JniPointerResult globalEnv_FromReflectedMethod(jobject method) { + attach_thread(); + jmethodID _result = (*jniEnv)->FromReflectedMethod(jniEnv, method); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniPointerResult){.value = NULL, .exception = _exception}; + } + return (JniPointerResult){.value = _result, .exception = NULL}; +} + +JniPointerResult globalEnv_FromReflectedField(jobject field) { + attach_thread(); + jfieldID _result = (*jniEnv)->FromReflectedField(jniEnv, field); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniPointerResult){.value = NULL, .exception = _exception}; + } + return (JniPointerResult){.value = _result, .exception = NULL}; +} + +JniResult globalEnv_ToReflectedMethod(jclass cls, + jmethodID methodId, + jboolean isStatic) { + attach_thread(); + jobject _result = + (*jniEnv)->ToReflectedMethod(jniEnv, cls, methodId, isStatic); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + _result = to_global_ref(_result); + return (JniResult){.value = {.l = _result}, .exception = NULL}; +} + +JniClassLookupResult globalEnv_GetSuperclass(jclass clazz) { + attach_thread(); + jclass _result = (*jniEnv)->GetSuperclass(jniEnv, clazz); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniClassLookupResult){.value = NULL, .exception = _exception}; + } + _result = to_global_ref(_result); + return (JniClassLookupResult){.value = _result, .exception = NULL}; +} + +JniResult globalEnv_IsAssignableFrom(jclass clazz1, jclass clazz2) { + attach_thread(); + jboolean _result = (*jniEnv)->IsAssignableFrom(jniEnv, clazz1, clazz2); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.z = _result}, .exception = NULL}; +} + +JniResult globalEnv_ToReflectedField(jclass cls, + jfieldID fieldID, + jboolean isStatic) { + attach_thread(); + jobject _result = (*jniEnv)->ToReflectedField(jniEnv, cls, fieldID, isStatic); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + _result = to_global_ref(_result); + return (JniResult){.value = {.l = _result}, .exception = NULL}; +} + +JniResult globalEnv_Throw(jthrowable obj) { + attach_thread(); + jint _result = (*jniEnv)->Throw(jniEnv, obj); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.i = _result}, .exception = NULL}; +} + +JniResult globalEnv_ThrowNew(jclass clazz, char* message) { + attach_thread(); + jint _result = (*jniEnv)->ThrowNew(jniEnv, clazz, message); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.i = _result}, .exception = NULL}; +} + +JniResult globalEnv_ExceptionOccurred() { + attach_thread(); + jthrowable _result = (*jniEnv)->ExceptionOccurred(jniEnv); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + _result = to_global_ref(_result); + return (JniResult){.value = {.l = _result}, .exception = NULL}; +} + +jthrowable globalEnv_ExceptionDescribe() { + attach_thread(); + (*jniEnv)->ExceptionDescribe(jniEnv); + return NULL; +} + +jthrowable globalEnv_ExceptionClear() { + attach_thread(); + (*jniEnv)->ExceptionClear(jniEnv); + return NULL; +} + +jthrowable globalEnv_FatalError(char* msg) { + attach_thread(); + (*jniEnv)->FatalError(jniEnv, msg); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +JniResult globalEnv_PushLocalFrame(jint capacity) { + attach_thread(); + jint _result = (*jniEnv)->PushLocalFrame(jniEnv, capacity); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.i = _result}, .exception = NULL}; +} + +JniResult globalEnv_PopLocalFrame(jobject result) { + attach_thread(); + jobject _result = (*jniEnv)->PopLocalFrame(jniEnv, result); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + _result = to_global_ref(_result); + return (JniResult){.value = {.l = _result}, .exception = NULL}; +} + +JniResult globalEnv_NewGlobalRef(jobject obj) { + attach_thread(); + jobject _result = (*jniEnv)->NewGlobalRef(jniEnv, obj); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.l = _result}, .exception = NULL}; +} + +jthrowable globalEnv_DeleteGlobalRef(jobject globalRef) { + attach_thread(); + (*jniEnv)->DeleteGlobalRef(jniEnv, globalRef); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_DeleteLocalRef(jobject localRef) { + attach_thread(); + (*jniEnv)->DeleteLocalRef(jniEnv, localRef); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +JniResult globalEnv_IsSameObject(jobject ref1, jobject ref2) { + attach_thread(); + jboolean _result = (*jniEnv)->IsSameObject(jniEnv, ref1, ref2); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.z = _result}, .exception = NULL}; +} + +JniResult globalEnv_NewLocalRef(jobject obj) { + attach_thread(); + jobject _result = (*jniEnv)->NewLocalRef(jniEnv, obj); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.l = _result}, .exception = NULL}; +} + +JniResult globalEnv_EnsureLocalCapacity(jint capacity) { + attach_thread(); + jint _result = (*jniEnv)->EnsureLocalCapacity(jniEnv, capacity); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.i = _result}, .exception = NULL}; +} + +JniResult globalEnv_AllocObject(jclass clazz) { + attach_thread(); + jobject _result = (*jniEnv)->AllocObject(jniEnv, clazz); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + _result = to_global_ref(_result); + return (JniResult){.value = {.l = _result}, .exception = NULL}; +} + +JniResult globalEnv_NewObject(jclass clazz, jmethodID methodID) { + attach_thread(); + jobject _result = (*jniEnv)->NewObject(jniEnv, clazz, methodID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + _result = to_global_ref(_result); + return (JniResult){.value = {.l = _result}, .exception = NULL}; +} + +JniResult globalEnv_NewObjectA(jclass clazz, jmethodID methodID, jvalue* args) { + attach_thread(); + jobject _result = (*jniEnv)->NewObjectA(jniEnv, clazz, methodID, args); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + _result = to_global_ref(_result); + return (JniResult){.value = {.l = _result}, .exception = NULL}; +} + +JniClassLookupResult globalEnv_GetObjectClass(jobject obj) { + attach_thread(); + jclass _result = (*jniEnv)->GetObjectClass(jniEnv, obj); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniClassLookupResult){.value = NULL, .exception = _exception}; + } + _result = to_global_ref(_result); + return (JniClassLookupResult){.value = _result, .exception = NULL}; +} + +JniResult globalEnv_IsInstanceOf(jobject obj, jclass clazz) { + attach_thread(); + jboolean _result = (*jniEnv)->IsInstanceOf(jniEnv, obj, clazz); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.z = _result}, .exception = NULL}; +} + +JniPointerResult globalEnv_GetMethodID(jclass clazz, char* name, char* sig) { + attach_thread(); + jmethodID _result = (*jniEnv)->GetMethodID(jniEnv, clazz, name, sig); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniPointerResult){.value = NULL, .exception = _exception}; + } + return (JniPointerResult){.value = _result, .exception = NULL}; +} + +JniResult globalEnv_CallObjectMethod(jobject obj, jmethodID methodID) { + attach_thread(); + jobject _result = (*jniEnv)->CallObjectMethod(jniEnv, obj, methodID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + _result = to_global_ref(_result); + return (JniResult){.value = {.l = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallObjectMethodA(jobject obj, + jmethodID methodID, + jvalue* args) { + attach_thread(); + jobject _result = (*jniEnv)->CallObjectMethodA(jniEnv, obj, methodID, args); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + _result = to_global_ref(_result); + return (JniResult){.value = {.l = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallBooleanMethod(jobject obj, jmethodID methodID) { + attach_thread(); + jboolean _result = (*jniEnv)->CallBooleanMethod(jniEnv, obj, methodID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.z = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallBooleanMethodA(jobject obj, + jmethodID methodId, + jvalue* args) { + attach_thread(); + jboolean _result = (*jniEnv)->CallBooleanMethodA(jniEnv, obj, methodId, args); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.z = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallByteMethod(jobject obj, jmethodID methodID) { + attach_thread(); + jbyte _result = (*jniEnv)->CallByteMethod(jniEnv, obj, methodID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.b = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallByteMethodA(jobject obj, + jmethodID methodID, + jvalue* args) { + attach_thread(); + jbyte _result = (*jniEnv)->CallByteMethodA(jniEnv, obj, methodID, args); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.b = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallCharMethod(jobject obj, jmethodID methodID) { + attach_thread(); + jchar _result = (*jniEnv)->CallCharMethod(jniEnv, obj, methodID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.c = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallCharMethodA(jobject obj, + jmethodID methodID, + jvalue* args) { + attach_thread(); + jchar _result = (*jniEnv)->CallCharMethodA(jniEnv, obj, methodID, args); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.c = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallShortMethod(jobject obj, jmethodID methodID) { + attach_thread(); + jshort _result = (*jniEnv)->CallShortMethod(jniEnv, obj, methodID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.s = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallShortMethodA(jobject obj, + jmethodID methodID, + jvalue* args) { + attach_thread(); + jshort _result = (*jniEnv)->CallShortMethodA(jniEnv, obj, methodID, args); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.s = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallIntMethod(jobject obj, jmethodID methodID) { + attach_thread(); + jint _result = (*jniEnv)->CallIntMethod(jniEnv, obj, methodID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.i = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallIntMethodA(jobject obj, + jmethodID methodID, + jvalue* args) { + attach_thread(); + jint _result = (*jniEnv)->CallIntMethodA(jniEnv, obj, methodID, args); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.i = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallLongMethod(jobject obj, jmethodID methodID) { + attach_thread(); + jlong _result = (*jniEnv)->CallLongMethod(jniEnv, obj, methodID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.j = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallLongMethodA(jobject obj, + jmethodID methodID, + jvalue* args) { + attach_thread(); + jlong _result = (*jniEnv)->CallLongMethodA(jniEnv, obj, methodID, args); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.j = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallFloatMethod(jobject obj, jmethodID methodID) { + attach_thread(); + jfloat _result = (*jniEnv)->CallFloatMethod(jniEnv, obj, methodID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.f = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallFloatMethodA(jobject obj, + jmethodID methodID, + jvalue* args) { + attach_thread(); + jfloat _result = (*jniEnv)->CallFloatMethodA(jniEnv, obj, methodID, args); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.f = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallDoubleMethod(jobject obj, jmethodID methodID) { + attach_thread(); + jdouble _result = (*jniEnv)->CallDoubleMethod(jniEnv, obj, methodID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.d = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallDoubleMethodA(jobject obj, + jmethodID methodID, + jvalue* args) { + attach_thread(); + jdouble _result = (*jniEnv)->CallDoubleMethodA(jniEnv, obj, methodID, args); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.d = _result}, .exception = NULL}; +} + +jthrowable globalEnv_CallVoidMethod(jobject obj, jmethodID methodID) { + attach_thread(); + (*jniEnv)->CallVoidMethod(jniEnv, obj, methodID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_CallVoidMethodA(jobject obj, + jmethodID methodID, + jvalue* args) { + attach_thread(); + (*jniEnv)->CallVoidMethodA(jniEnv, obj, methodID, args); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +JniResult globalEnv_CallNonvirtualObjectMethod(jobject obj, + jclass clazz, + jmethodID methodID) { + attach_thread(); + jobject _result = + (*jniEnv)->CallNonvirtualObjectMethod(jniEnv, obj, clazz, methodID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + _result = to_global_ref(_result); + return (JniResult){.value = {.l = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallNonvirtualObjectMethodA(jobject obj, + jclass clazz, + jmethodID methodID, + jvalue* args) { + attach_thread(); + jobject _result = (*jniEnv)->CallNonvirtualObjectMethodA(jniEnv, obj, clazz, + methodID, args); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + _result = to_global_ref(_result); + return (JniResult){.value = {.l = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallNonvirtualBooleanMethod(jobject obj, + jclass clazz, + jmethodID methodID) { + attach_thread(); + jboolean _result = + (*jniEnv)->CallNonvirtualBooleanMethod(jniEnv, obj, clazz, methodID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.z = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallNonvirtualBooleanMethodA(jobject obj, + jclass clazz, + jmethodID methodID, + jvalue* args) { + attach_thread(); + jboolean _result = (*jniEnv)->CallNonvirtualBooleanMethodA(jniEnv, obj, clazz, + methodID, args); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.z = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallNonvirtualByteMethod(jobject obj, + jclass clazz, + jmethodID methodID) { + attach_thread(); + jbyte _result = + (*jniEnv)->CallNonvirtualByteMethod(jniEnv, obj, clazz, methodID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.b = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallNonvirtualByteMethodA(jobject obj, + jclass clazz, + jmethodID methodID, + jvalue* args) { + attach_thread(); + jbyte _result = + (*jniEnv)->CallNonvirtualByteMethodA(jniEnv, obj, clazz, methodID, args); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.b = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallNonvirtualCharMethod(jobject obj, + jclass clazz, + jmethodID methodID) { + attach_thread(); + jchar _result = + (*jniEnv)->CallNonvirtualCharMethod(jniEnv, obj, clazz, methodID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.c = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallNonvirtualCharMethodA(jobject obj, + jclass clazz, + jmethodID methodID, + jvalue* args) { + attach_thread(); + jchar _result = + (*jniEnv)->CallNonvirtualCharMethodA(jniEnv, obj, clazz, methodID, args); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.c = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallNonvirtualShortMethod(jobject obj, + jclass clazz, + jmethodID methodID) { + attach_thread(); + jshort _result = + (*jniEnv)->CallNonvirtualShortMethod(jniEnv, obj, clazz, methodID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.s = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallNonvirtualShortMethodA(jobject obj, + jclass clazz, + jmethodID methodID, + jvalue* args) { + attach_thread(); + jshort _result = + (*jniEnv)->CallNonvirtualShortMethodA(jniEnv, obj, clazz, methodID, args); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.s = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallNonvirtualIntMethod(jobject obj, + jclass clazz, + jmethodID methodID) { + attach_thread(); + jint _result = + (*jniEnv)->CallNonvirtualIntMethod(jniEnv, obj, clazz, methodID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.i = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallNonvirtualIntMethodA(jobject obj, + jclass clazz, + jmethodID methodID, + jvalue* args) { + attach_thread(); + jint _result = + (*jniEnv)->CallNonvirtualIntMethodA(jniEnv, obj, clazz, methodID, args); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.i = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallNonvirtualLongMethod(jobject obj, + jclass clazz, + jmethodID methodID) { + attach_thread(); + jlong _result = + (*jniEnv)->CallNonvirtualLongMethod(jniEnv, obj, clazz, methodID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.j = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallNonvirtualLongMethodA(jobject obj, + jclass clazz, + jmethodID methodID, + jvalue* args) { + attach_thread(); + jlong _result = + (*jniEnv)->CallNonvirtualLongMethodA(jniEnv, obj, clazz, methodID, args); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.j = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallNonvirtualFloatMethod(jobject obj, + jclass clazz, + jmethodID methodID) { + attach_thread(); + jfloat _result = + (*jniEnv)->CallNonvirtualFloatMethod(jniEnv, obj, clazz, methodID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.f = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallNonvirtualFloatMethodA(jobject obj, + jclass clazz, + jmethodID methodID, + jvalue* args) { + attach_thread(); + jfloat _result = + (*jniEnv)->CallNonvirtualFloatMethodA(jniEnv, obj, clazz, methodID, args); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.f = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallNonvirtualDoubleMethod(jobject obj, + jclass clazz, + jmethodID methodID) { + attach_thread(); + jdouble _result = + (*jniEnv)->CallNonvirtualDoubleMethod(jniEnv, obj, clazz, methodID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.d = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallNonvirtualDoubleMethodA(jobject obj, + jclass clazz, + jmethodID methodID, + jvalue* args) { + attach_thread(); + jdouble _result = (*jniEnv)->CallNonvirtualDoubleMethodA(jniEnv, obj, clazz, + methodID, args); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.d = _result}, .exception = NULL}; +} + +jthrowable globalEnv_CallNonvirtualVoidMethod(jobject obj, + jclass clazz, + jmethodID methodID) { + attach_thread(); + (*jniEnv)->CallNonvirtualVoidMethod(jniEnv, obj, clazz, methodID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_CallNonvirtualVoidMethodA(jobject obj, + jclass clazz, + jmethodID methodID, + jvalue* args) { + attach_thread(); + (*jniEnv)->CallNonvirtualVoidMethodA(jniEnv, obj, clazz, methodID, args); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +JniPointerResult globalEnv_GetFieldID(jclass clazz, char* name, char* sig) { + attach_thread(); + jfieldID _result = (*jniEnv)->GetFieldID(jniEnv, clazz, name, sig); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniPointerResult){.value = NULL, .exception = _exception}; + } + return (JniPointerResult){.value = _result, .exception = NULL}; +} + +JniResult globalEnv_GetObjectField(jobject obj, jfieldID fieldID) { + attach_thread(); + jobject _result = (*jniEnv)->GetObjectField(jniEnv, obj, fieldID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + _result = to_global_ref(_result); + return (JniResult){.value = {.l = _result}, .exception = NULL}; +} + +JniResult globalEnv_GetBooleanField(jobject obj, jfieldID fieldID) { + attach_thread(); + jboolean _result = (*jniEnv)->GetBooleanField(jniEnv, obj, fieldID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.z = _result}, .exception = NULL}; +} + +JniResult globalEnv_GetByteField(jobject obj, jfieldID fieldID) { + attach_thread(); + jbyte _result = (*jniEnv)->GetByteField(jniEnv, obj, fieldID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.b = _result}, .exception = NULL}; +} + +JniResult globalEnv_GetCharField(jobject obj, jfieldID fieldID) { + attach_thread(); + jchar _result = (*jniEnv)->GetCharField(jniEnv, obj, fieldID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.c = _result}, .exception = NULL}; +} + +JniResult globalEnv_GetShortField(jobject obj, jfieldID fieldID) { + attach_thread(); + jshort _result = (*jniEnv)->GetShortField(jniEnv, obj, fieldID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.s = _result}, .exception = NULL}; +} + +JniResult globalEnv_GetIntField(jobject obj, jfieldID fieldID) { + attach_thread(); + jint _result = (*jniEnv)->GetIntField(jniEnv, obj, fieldID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.i = _result}, .exception = NULL}; +} + +JniResult globalEnv_GetLongField(jobject obj, jfieldID fieldID) { + attach_thread(); + jlong _result = (*jniEnv)->GetLongField(jniEnv, obj, fieldID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.j = _result}, .exception = NULL}; +} + +JniResult globalEnv_GetFloatField(jobject obj, jfieldID fieldID) { + attach_thread(); + jfloat _result = (*jniEnv)->GetFloatField(jniEnv, obj, fieldID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.f = _result}, .exception = NULL}; +} + +JniResult globalEnv_GetDoubleField(jobject obj, jfieldID fieldID) { + attach_thread(); + jdouble _result = (*jniEnv)->GetDoubleField(jniEnv, obj, fieldID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.d = _result}, .exception = NULL}; +} + +jthrowable globalEnv_SetObjectField(jobject obj, + jfieldID fieldID, + jobject val) { + attach_thread(); + (*jniEnv)->SetObjectField(jniEnv, obj, fieldID, val); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_SetBooleanField(jobject obj, + jfieldID fieldID, + jboolean val) { + attach_thread(); + (*jniEnv)->SetBooleanField(jniEnv, obj, fieldID, val); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_SetByteField(jobject obj, jfieldID fieldID, jbyte val) { + attach_thread(); + (*jniEnv)->SetByteField(jniEnv, obj, fieldID, val); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_SetCharField(jobject obj, jfieldID fieldID, jchar val) { + attach_thread(); + (*jniEnv)->SetCharField(jniEnv, obj, fieldID, val); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_SetShortField(jobject obj, jfieldID fieldID, jshort val) { + attach_thread(); + (*jniEnv)->SetShortField(jniEnv, obj, fieldID, val); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_SetIntField(jobject obj, jfieldID fieldID, jint val) { + attach_thread(); + (*jniEnv)->SetIntField(jniEnv, obj, fieldID, val); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_SetLongField(jobject obj, jfieldID fieldID, jlong val) { + attach_thread(); + (*jniEnv)->SetLongField(jniEnv, obj, fieldID, val); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_SetFloatField(jobject obj, jfieldID fieldID, jfloat val) { + attach_thread(); + (*jniEnv)->SetFloatField(jniEnv, obj, fieldID, val); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_SetDoubleField(jobject obj, + jfieldID fieldID, + jdouble val) { + attach_thread(); + (*jniEnv)->SetDoubleField(jniEnv, obj, fieldID, val); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +JniPointerResult globalEnv_GetStaticMethodID(jclass clazz, + char* name, + char* sig) { + attach_thread(); + jmethodID _result = (*jniEnv)->GetStaticMethodID(jniEnv, clazz, name, sig); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniPointerResult){.value = NULL, .exception = _exception}; + } + return (JniPointerResult){.value = _result, .exception = NULL}; +} + +JniResult globalEnv_CallStaticObjectMethod(jclass clazz, jmethodID methodID) { + attach_thread(); + jobject _result = (*jniEnv)->CallStaticObjectMethod(jniEnv, clazz, methodID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + _result = to_global_ref(_result); + return (JniResult){.value = {.l = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallStaticObjectMethodA(jclass clazz, + jmethodID methodID, + jvalue* args) { + attach_thread(); + jobject _result = + (*jniEnv)->CallStaticObjectMethodA(jniEnv, clazz, methodID, args); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + _result = to_global_ref(_result); + return (JniResult){.value = {.l = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallStaticBooleanMethod(jclass clazz, jmethodID methodID) { + attach_thread(); + jboolean _result = + (*jniEnv)->CallStaticBooleanMethod(jniEnv, clazz, methodID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.z = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallStaticBooleanMethodA(jclass clazz, + jmethodID methodID, + jvalue* args) { + attach_thread(); + jboolean _result = + (*jniEnv)->CallStaticBooleanMethodA(jniEnv, clazz, methodID, args); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.z = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallStaticByteMethod(jclass clazz, jmethodID methodID) { + attach_thread(); + jbyte _result = (*jniEnv)->CallStaticByteMethod(jniEnv, clazz, methodID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.b = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallStaticByteMethodA(jclass clazz, + jmethodID methodID, + jvalue* args) { + attach_thread(); + jbyte _result = + (*jniEnv)->CallStaticByteMethodA(jniEnv, clazz, methodID, args); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.b = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallStaticCharMethod(jclass clazz, jmethodID methodID) { + attach_thread(); + jchar _result = (*jniEnv)->CallStaticCharMethod(jniEnv, clazz, methodID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.c = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallStaticCharMethodA(jclass clazz, + jmethodID methodID, + jvalue* args) { + attach_thread(); + jchar _result = + (*jniEnv)->CallStaticCharMethodA(jniEnv, clazz, methodID, args); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.c = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallStaticShortMethod(jclass clazz, jmethodID methodID) { + attach_thread(); + jshort _result = (*jniEnv)->CallStaticShortMethod(jniEnv, clazz, methodID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.s = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallStaticShortMethodA(jclass clazz, + jmethodID methodID, + jvalue* args) { + attach_thread(); + jshort _result = + (*jniEnv)->CallStaticShortMethodA(jniEnv, clazz, methodID, args); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.s = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallStaticIntMethod(jclass clazz, jmethodID methodID) { + attach_thread(); + jint _result = (*jniEnv)->CallStaticIntMethod(jniEnv, clazz, methodID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.i = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallStaticIntMethodA(jclass clazz, + jmethodID methodID, + jvalue* args) { + attach_thread(); + jint _result = (*jniEnv)->CallStaticIntMethodA(jniEnv, clazz, methodID, args); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.i = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallStaticLongMethod(jclass clazz, jmethodID methodID) { + attach_thread(); + jlong _result = (*jniEnv)->CallStaticLongMethod(jniEnv, clazz, methodID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.j = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallStaticLongMethodA(jclass clazz, + jmethodID methodID, + jvalue* args) { + attach_thread(); + jlong _result = + (*jniEnv)->CallStaticLongMethodA(jniEnv, clazz, methodID, args); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.j = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallStaticFloatMethod(jclass clazz, jmethodID methodID) { + attach_thread(); + jfloat _result = (*jniEnv)->CallStaticFloatMethod(jniEnv, clazz, methodID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.f = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallStaticFloatMethodA(jclass clazz, + jmethodID methodID, + jvalue* args) { + attach_thread(); + jfloat _result = + (*jniEnv)->CallStaticFloatMethodA(jniEnv, clazz, methodID, args); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.f = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallStaticDoubleMethod(jclass clazz, jmethodID methodID) { + attach_thread(); + jdouble _result = (*jniEnv)->CallStaticDoubleMethod(jniEnv, clazz, methodID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.d = _result}, .exception = NULL}; +} + +JniResult globalEnv_CallStaticDoubleMethodA(jclass clazz, + jmethodID methodID, + jvalue* args) { + attach_thread(); + jdouble _result = + (*jniEnv)->CallStaticDoubleMethodA(jniEnv, clazz, methodID, args); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.d = _result}, .exception = NULL}; +} + +jthrowable globalEnv_CallStaticVoidMethod(jclass clazz, jmethodID methodID) { + attach_thread(); + (*jniEnv)->CallStaticVoidMethod(jniEnv, clazz, methodID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_CallStaticVoidMethodA(jclass clazz, + jmethodID methodID, + jvalue* args) { + attach_thread(); + (*jniEnv)->CallStaticVoidMethodA(jniEnv, clazz, methodID, args); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +JniPointerResult globalEnv_GetStaticFieldID(jclass clazz, + char* name, + char* sig) { + attach_thread(); + jfieldID _result = (*jniEnv)->GetStaticFieldID(jniEnv, clazz, name, sig); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniPointerResult){.value = NULL, .exception = _exception}; + } + return (JniPointerResult){.value = _result, .exception = NULL}; +} + +JniResult globalEnv_GetStaticObjectField(jclass clazz, jfieldID fieldID) { + attach_thread(); + jobject _result = (*jniEnv)->GetStaticObjectField(jniEnv, clazz, fieldID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + _result = to_global_ref(_result); + return (JniResult){.value = {.l = _result}, .exception = NULL}; +} + +JniResult globalEnv_GetStaticBooleanField(jclass clazz, jfieldID fieldID) { + attach_thread(); + jboolean _result = (*jniEnv)->GetStaticBooleanField(jniEnv, clazz, fieldID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.z = _result}, .exception = NULL}; +} + +JniResult globalEnv_GetStaticByteField(jclass clazz, jfieldID fieldID) { + attach_thread(); + jbyte _result = (*jniEnv)->GetStaticByteField(jniEnv, clazz, fieldID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.b = _result}, .exception = NULL}; +} + +JniResult globalEnv_GetStaticCharField(jclass clazz, jfieldID fieldID) { + attach_thread(); + jchar _result = (*jniEnv)->GetStaticCharField(jniEnv, clazz, fieldID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.c = _result}, .exception = NULL}; +} + +JniResult globalEnv_GetStaticShortField(jclass clazz, jfieldID fieldID) { + attach_thread(); + jshort _result = (*jniEnv)->GetStaticShortField(jniEnv, clazz, fieldID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.s = _result}, .exception = NULL}; +} + +JniResult globalEnv_GetStaticIntField(jclass clazz, jfieldID fieldID) { + attach_thread(); + jint _result = (*jniEnv)->GetStaticIntField(jniEnv, clazz, fieldID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.i = _result}, .exception = NULL}; +} + +JniResult globalEnv_GetStaticLongField(jclass clazz, jfieldID fieldID) { + attach_thread(); + jlong _result = (*jniEnv)->GetStaticLongField(jniEnv, clazz, fieldID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.j = _result}, .exception = NULL}; +} + +JniResult globalEnv_GetStaticFloatField(jclass clazz, jfieldID fieldID) { + attach_thread(); + jfloat _result = (*jniEnv)->GetStaticFloatField(jniEnv, clazz, fieldID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.f = _result}, .exception = NULL}; +} + +JniResult globalEnv_GetStaticDoubleField(jclass clazz, jfieldID fieldID) { + attach_thread(); + jdouble _result = (*jniEnv)->GetStaticDoubleField(jniEnv, clazz, fieldID); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.d = _result}, .exception = NULL}; +} + +jthrowable globalEnv_SetStaticObjectField(jclass clazz, + jfieldID fieldID, + jobject val) { + attach_thread(); + (*jniEnv)->SetStaticObjectField(jniEnv, clazz, fieldID, val); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_SetStaticBooleanField(jclass clazz, + jfieldID fieldID, + jboolean val) { + attach_thread(); + (*jniEnv)->SetStaticBooleanField(jniEnv, clazz, fieldID, val); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_SetStaticByteField(jclass clazz, + jfieldID fieldID, + jbyte val) { + attach_thread(); + (*jniEnv)->SetStaticByteField(jniEnv, clazz, fieldID, val); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_SetStaticCharField(jclass clazz, + jfieldID fieldID, + jchar val) { + attach_thread(); + (*jniEnv)->SetStaticCharField(jniEnv, clazz, fieldID, val); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_SetStaticShortField(jclass clazz, + jfieldID fieldID, + jshort val) { + attach_thread(); + (*jniEnv)->SetStaticShortField(jniEnv, clazz, fieldID, val); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_SetStaticIntField(jclass clazz, + jfieldID fieldID, + jint val) { + attach_thread(); + (*jniEnv)->SetStaticIntField(jniEnv, clazz, fieldID, val); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_SetStaticLongField(jclass clazz, + jfieldID fieldID, + jlong val) { + attach_thread(); + (*jniEnv)->SetStaticLongField(jniEnv, clazz, fieldID, val); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_SetStaticFloatField(jclass clazz, + jfieldID fieldID, + jfloat val) { + attach_thread(); + (*jniEnv)->SetStaticFloatField(jniEnv, clazz, fieldID, val); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_SetStaticDoubleField(jclass clazz, + jfieldID fieldID, + jdouble val) { + attach_thread(); + (*jniEnv)->SetStaticDoubleField(jniEnv, clazz, fieldID, val); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +JniResult globalEnv_NewString(jchar* unicodeChars, jsize len) { + attach_thread(); + jstring _result = (*jniEnv)->NewString(jniEnv, unicodeChars, len); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + _result = to_global_ref(_result); + return (JniResult){.value = {.l = _result}, .exception = NULL}; +} + +JniResult globalEnv_GetStringLength(jstring string) { + attach_thread(); + jsize _result = (*jniEnv)->GetStringLength(jniEnv, string); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.i = _result}, .exception = NULL}; +} + +JniPointerResult globalEnv_GetStringChars(jstring string, jboolean* isCopy) { + attach_thread(); + const jchar* _result = (*jniEnv)->GetStringChars(jniEnv, string, isCopy); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniPointerResult){.value = NULL, .exception = _exception}; + } + return (JniPointerResult){.value = _result, .exception = NULL}; +} + +jthrowable globalEnv_ReleaseStringChars(jstring string, jchar* isCopy) { + attach_thread(); + (*jniEnv)->ReleaseStringChars(jniEnv, string, isCopy); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +JniResult globalEnv_NewStringUTF(char* bytes) { + attach_thread(); + jstring _result = (*jniEnv)->NewStringUTF(jniEnv, bytes); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + _result = to_global_ref(_result); + return (JniResult){.value = {.l = _result}, .exception = NULL}; +} + +JniResult globalEnv_GetStringUTFLength(jstring string) { + attach_thread(); + jsize _result = (*jniEnv)->GetStringUTFLength(jniEnv, string); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.i = _result}, .exception = NULL}; +} + +JniPointerResult globalEnv_GetStringUTFChars(jstring string, jboolean* isCopy) { + attach_thread(); + const char* _result = (*jniEnv)->GetStringUTFChars(jniEnv, string, isCopy); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniPointerResult){.value = NULL, .exception = _exception}; + } + return (JniPointerResult){.value = _result, .exception = NULL}; +} + +jthrowable globalEnv_ReleaseStringUTFChars(jstring string, char* utf) { + attach_thread(); + (*jniEnv)->ReleaseStringUTFChars(jniEnv, string, utf); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +JniResult globalEnv_GetArrayLength(jarray array) { + attach_thread(); + jsize _result = (*jniEnv)->GetArrayLength(jniEnv, array); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.i = _result}, .exception = NULL}; +} + +JniResult globalEnv_NewObjectArray(jsize length, + jclass elementClass, + jobject initialElement) { + attach_thread(); + jobjectArray _result = + (*jniEnv)->NewObjectArray(jniEnv, length, elementClass, initialElement); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + _result = to_global_ref(_result); + return (JniResult){.value = {.l = _result}, .exception = NULL}; +} + +JniResult globalEnv_GetObjectArrayElement(jobjectArray array, jsize index) { + attach_thread(); + jobject _result = (*jniEnv)->GetObjectArrayElement(jniEnv, array, index); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + _result = to_global_ref(_result); + return (JniResult){.value = {.l = _result}, .exception = NULL}; +} + +jthrowable globalEnv_SetObjectArrayElement(jobjectArray array, + jsize index, + jobject val) { + attach_thread(); + (*jniEnv)->SetObjectArrayElement(jniEnv, array, index, val); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +JniResult globalEnv_NewBooleanArray(jsize length) { + attach_thread(); + jbooleanArray _result = (*jniEnv)->NewBooleanArray(jniEnv, length); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + _result = to_global_ref(_result); + return (JniResult){.value = {.l = _result}, .exception = NULL}; +} + +JniResult globalEnv_NewByteArray(jsize length) { + attach_thread(); + jbyteArray _result = (*jniEnv)->NewByteArray(jniEnv, length); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + _result = to_global_ref(_result); + return (JniResult){.value = {.l = _result}, .exception = NULL}; +} + +JniResult globalEnv_NewCharArray(jsize length) { + attach_thread(); + jcharArray _result = (*jniEnv)->NewCharArray(jniEnv, length); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + _result = to_global_ref(_result); + return (JniResult){.value = {.l = _result}, .exception = NULL}; +} + +JniResult globalEnv_NewShortArray(jsize length) { + attach_thread(); + jshortArray _result = (*jniEnv)->NewShortArray(jniEnv, length); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + _result = to_global_ref(_result); + return (JniResult){.value = {.l = _result}, .exception = NULL}; +} + +JniResult globalEnv_NewIntArray(jsize length) { + attach_thread(); + jintArray _result = (*jniEnv)->NewIntArray(jniEnv, length); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + _result = to_global_ref(_result); + return (JniResult){.value = {.l = _result}, .exception = NULL}; +} + +JniResult globalEnv_NewLongArray(jsize length) { + attach_thread(); + jlongArray _result = (*jniEnv)->NewLongArray(jniEnv, length); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + _result = to_global_ref(_result); + return (JniResult){.value = {.l = _result}, .exception = NULL}; +} + +JniResult globalEnv_NewFloatArray(jsize length) { + attach_thread(); + jfloatArray _result = (*jniEnv)->NewFloatArray(jniEnv, length); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + _result = to_global_ref(_result); + return (JniResult){.value = {.l = _result}, .exception = NULL}; +} + +JniResult globalEnv_NewDoubleArray(jsize length) { + attach_thread(); + jdoubleArray _result = (*jniEnv)->NewDoubleArray(jniEnv, length); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + _result = to_global_ref(_result); + return (JniResult){.value = {.l = _result}, .exception = NULL}; +} + +JniPointerResult globalEnv_GetBooleanArrayElements(jbooleanArray array, + jboolean* isCopy) { + attach_thread(); + jboolean* _result = (*jniEnv)->GetBooleanArrayElements(jniEnv, array, isCopy); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniPointerResult){.value = NULL, .exception = _exception}; + } + return (JniPointerResult){.value = _result, .exception = NULL}; +} + +JniPointerResult globalEnv_GetByteArrayElements(jbyteArray array, + jboolean* isCopy) { + attach_thread(); + jbyte* _result = (*jniEnv)->GetByteArrayElements(jniEnv, array, isCopy); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniPointerResult){.value = NULL, .exception = _exception}; + } + return (JniPointerResult){.value = _result, .exception = NULL}; +} + +JniPointerResult globalEnv_GetCharArrayElements(jcharArray array, + jboolean* isCopy) { + attach_thread(); + jchar* _result = (*jniEnv)->GetCharArrayElements(jniEnv, array, isCopy); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniPointerResult){.value = NULL, .exception = _exception}; + } + return (JniPointerResult){.value = _result, .exception = NULL}; +} + +JniPointerResult globalEnv_GetShortArrayElements(jshortArray array, + jboolean* isCopy) { + attach_thread(); + jshort* _result = (*jniEnv)->GetShortArrayElements(jniEnv, array, isCopy); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniPointerResult){.value = NULL, .exception = _exception}; + } + return (JniPointerResult){.value = _result, .exception = NULL}; +} + +JniPointerResult globalEnv_GetIntArrayElements(jintArray array, + jboolean* isCopy) { + attach_thread(); + jint* _result = (*jniEnv)->GetIntArrayElements(jniEnv, array, isCopy); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniPointerResult){.value = NULL, .exception = _exception}; + } + return (JniPointerResult){.value = _result, .exception = NULL}; +} + +JniPointerResult globalEnv_GetLongArrayElements(jlongArray array, + jboolean* isCopy) { + attach_thread(); + jlong* _result = (*jniEnv)->GetLongArrayElements(jniEnv, array, isCopy); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniPointerResult){.value = NULL, .exception = _exception}; + } + return (JniPointerResult){.value = _result, .exception = NULL}; +} + +JniPointerResult globalEnv_GetFloatArrayElements(jfloatArray array, + jboolean* isCopy) { + attach_thread(); + jfloat* _result = (*jniEnv)->GetFloatArrayElements(jniEnv, array, isCopy); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniPointerResult){.value = NULL, .exception = _exception}; + } + return (JniPointerResult){.value = _result, .exception = NULL}; +} + +JniPointerResult globalEnv_GetDoubleArrayElements(jdoubleArray array, + jboolean* isCopy) { + attach_thread(); + jdouble* _result = (*jniEnv)->GetDoubleArrayElements(jniEnv, array, isCopy); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniPointerResult){.value = NULL, .exception = _exception}; + } + return (JniPointerResult){.value = _result, .exception = NULL}; +} + +jthrowable globalEnv_ReleaseBooleanArrayElements(jbooleanArray array, + jboolean* elems, + jint mode) { + attach_thread(); + (*jniEnv)->ReleaseBooleanArrayElements(jniEnv, array, elems, mode); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_ReleaseByteArrayElements(jbyteArray array, + jbyte* elems, + jint mode) { + attach_thread(); + (*jniEnv)->ReleaseByteArrayElements(jniEnv, array, elems, mode); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_ReleaseCharArrayElements(jcharArray array, + jchar* elems, + jint mode) { + attach_thread(); + (*jniEnv)->ReleaseCharArrayElements(jniEnv, array, elems, mode); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_ReleaseShortArrayElements(jshortArray array, + jshort* elems, + jint mode) { + attach_thread(); + (*jniEnv)->ReleaseShortArrayElements(jniEnv, array, elems, mode); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_ReleaseIntArrayElements(jintArray array, + jint* elems, + jint mode) { + attach_thread(); + (*jniEnv)->ReleaseIntArrayElements(jniEnv, array, elems, mode); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_ReleaseLongArrayElements(jlongArray array, + jlong* elems, + jint mode) { + attach_thread(); + (*jniEnv)->ReleaseLongArrayElements(jniEnv, array, elems, mode); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_ReleaseFloatArrayElements(jfloatArray array, + jfloat* elems, + jint mode) { + attach_thread(); + (*jniEnv)->ReleaseFloatArrayElements(jniEnv, array, elems, mode); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_ReleaseDoubleArrayElements(jdoubleArray array, + jdouble* elems, + jint mode) { + attach_thread(); + (*jniEnv)->ReleaseDoubleArrayElements(jniEnv, array, elems, mode); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_GetBooleanArrayRegion(jbooleanArray array, + jsize start, + jsize len, + jboolean* buf) { + attach_thread(); + (*jniEnv)->GetBooleanArrayRegion(jniEnv, array, start, len, buf); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_GetByteArrayRegion(jbyteArray array, + jsize start, + jsize len, + jbyte* buf) { + attach_thread(); + (*jniEnv)->GetByteArrayRegion(jniEnv, array, start, len, buf); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_GetCharArrayRegion(jcharArray array, + jsize start, + jsize len, + jchar* buf) { + attach_thread(); + (*jniEnv)->GetCharArrayRegion(jniEnv, array, start, len, buf); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_GetShortArrayRegion(jshortArray array, + jsize start, + jsize len, + jshort* buf) { + attach_thread(); + (*jniEnv)->GetShortArrayRegion(jniEnv, array, start, len, buf); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_GetIntArrayRegion(jintArray array, + jsize start, + jsize len, + jint* buf) { + attach_thread(); + (*jniEnv)->GetIntArrayRegion(jniEnv, array, start, len, buf); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_GetLongArrayRegion(jlongArray array, + jsize start, + jsize len, + jlong* buf) { + attach_thread(); + (*jniEnv)->GetLongArrayRegion(jniEnv, array, start, len, buf); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_GetFloatArrayRegion(jfloatArray array, + jsize start, + jsize len, + jfloat* buf) { + attach_thread(); + (*jniEnv)->GetFloatArrayRegion(jniEnv, array, start, len, buf); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_GetDoubleArrayRegion(jdoubleArray array, + jsize start, + jsize len, + jdouble* buf) { + attach_thread(); + (*jniEnv)->GetDoubleArrayRegion(jniEnv, array, start, len, buf); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_SetBooleanArrayRegion(jbooleanArray array, + jsize start, + jsize len, + jboolean* buf) { + attach_thread(); + (*jniEnv)->SetBooleanArrayRegion(jniEnv, array, start, len, buf); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_SetByteArrayRegion(jbyteArray array, + jsize start, + jsize len, + jbyte* buf) { + attach_thread(); + (*jniEnv)->SetByteArrayRegion(jniEnv, array, start, len, buf); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_SetCharArrayRegion(jcharArray array, + jsize start, + jsize len, + jchar* buf) { + attach_thread(); + (*jniEnv)->SetCharArrayRegion(jniEnv, array, start, len, buf); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_SetShortArrayRegion(jshortArray array, + jsize start, + jsize len, + jshort* buf) { + attach_thread(); + (*jniEnv)->SetShortArrayRegion(jniEnv, array, start, len, buf); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_SetIntArrayRegion(jintArray array, + jsize start, + jsize len, + jint* buf) { + attach_thread(); + (*jniEnv)->SetIntArrayRegion(jniEnv, array, start, len, buf); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_SetLongArrayRegion(jlongArray array, + jsize start, + jsize len, + jlong* buf) { + attach_thread(); + (*jniEnv)->SetLongArrayRegion(jniEnv, array, start, len, buf); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_SetFloatArrayRegion(jfloatArray array, + jsize start, + jsize len, + jfloat* buf) { + attach_thread(); + (*jniEnv)->SetFloatArrayRegion(jniEnv, array, start, len, buf); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_SetDoubleArrayRegion(jdoubleArray array, + jsize start, + jsize len, + jdouble* buf) { + attach_thread(); + (*jniEnv)->SetDoubleArrayRegion(jniEnv, array, start, len, buf); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +JniResult globalEnv_RegisterNatives(jclass clazz, + JNINativeMethod* methods, + jint nMethods) { + attach_thread(); + jint _result = (*jniEnv)->RegisterNatives(jniEnv, clazz, methods, nMethods); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.i = _result}, .exception = NULL}; +} + +JniResult globalEnv_UnregisterNatives(jclass clazz) { + attach_thread(); + jint _result = (*jniEnv)->UnregisterNatives(jniEnv, clazz); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.i = _result}, .exception = NULL}; +} + +JniResult globalEnv_MonitorEnter(jobject obj) { + attach_thread(); + jint _result = (*jniEnv)->MonitorEnter(jniEnv, obj); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.i = _result}, .exception = NULL}; +} + +JniResult globalEnv_MonitorExit(jobject obj) { + attach_thread(); + jint _result = (*jniEnv)->MonitorExit(jniEnv, obj); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.i = _result}, .exception = NULL}; +} + +JniResult globalEnv_GetJavaVM(JavaVM** vm) { + attach_thread(); + jint _result = (*jniEnv)->GetJavaVM(jniEnv, vm); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.i = _result}, .exception = NULL}; +} + +jthrowable globalEnv_GetStringRegion(jstring str, + jsize start, + jsize len, + jchar* buf) { + attach_thread(); + (*jniEnv)->GetStringRegion(jniEnv, str, start, len, buf); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +jthrowable globalEnv_GetStringUTFRegion(jstring str, + jsize start, + jsize len, + char* buf) { + attach_thread(); + (*jniEnv)->GetStringUTFRegion(jniEnv, str, start, len, buf); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +JniPointerResult globalEnv_GetPrimitiveArrayCritical(jarray array, + jboolean* isCopy) { + attach_thread(); + void* _result = (*jniEnv)->GetPrimitiveArrayCritical(jniEnv, array, isCopy); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniPointerResult){.value = NULL, .exception = _exception}; + } + return (JniPointerResult){.value = _result, .exception = NULL}; +} + +jthrowable globalEnv_ReleasePrimitiveArrayCritical(jarray array, + void* carray, + jint mode) { + attach_thread(); + (*jniEnv)->ReleasePrimitiveArrayCritical(jniEnv, array, carray, mode); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +JniPointerResult globalEnv_GetStringCritical(jstring str, jboolean* isCopy) { + attach_thread(); + const jchar* _result = (*jniEnv)->GetStringCritical(jniEnv, str, isCopy); + return (JniPointerResult){.value = _result, .exception = NULL}; +} + +jthrowable globalEnv_ReleaseStringCritical(jstring str, jchar* carray) { + attach_thread(); + (*jniEnv)->ReleaseStringCritical(jniEnv, str, carray); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +JniResult globalEnv_NewWeakGlobalRef(jobject obj) { + attach_thread(); + jweak _result = (*jniEnv)->NewWeakGlobalRef(jniEnv, obj); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.l = _result}, .exception = NULL}; +} + +jthrowable globalEnv_DeleteWeakGlobalRef(jweak obj) { + attach_thread(); + (*jniEnv)->DeleteWeakGlobalRef(jniEnv, obj); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return _exception; + } + return NULL; +} + +JniResult globalEnv_ExceptionCheck() { + attach_thread(); + jboolean _result = (*jniEnv)->ExceptionCheck(jniEnv); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.z = _result}, .exception = NULL}; +} + +JniResult globalEnv_NewDirectByteBuffer(void* address, jlong capacity) { + attach_thread(); + jobject _result = (*jniEnv)->NewDirectByteBuffer(jniEnv, address, capacity); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + _result = to_global_ref(_result); + return (JniResult){.value = {.l = _result}, .exception = NULL}; +} + +JniPointerResult globalEnv_GetDirectBufferAddress(jobject buf) { + attach_thread(); + void* _result = (*jniEnv)->GetDirectBufferAddress(jniEnv, buf); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniPointerResult){.value = NULL, .exception = _exception}; + } + return (JniPointerResult){.value = _result, .exception = NULL}; +} + +JniResult globalEnv_GetDirectBufferCapacity(jobject buf) { + attach_thread(); + jlong _result = (*jniEnv)->GetDirectBufferCapacity(jniEnv, buf); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.j = _result}, .exception = NULL}; +} + +JniResult globalEnv_GetObjectRefType(jobject obj) { + attach_thread(); + int32_t _result = (*jniEnv)->GetObjectRefType(jniEnv, obj); + jthrowable _exception = check_exception(); + if (_exception != NULL) { + return (JniResult){.value = {.j = 0}, .exception = _exception}; + } + return (JniResult){.value = {.i = _result}, .exception = NULL}; +} + +GlobalJniEnvStruct globalJniEnv = { + .reserved0 = NULL, + .reserved1 = NULL, + .reserved2 = NULL, + .reserved3 = NULL, + .GetVersion = globalEnv_GetVersion, + .DefineClass = globalEnv_DefineClass, + .FindClass = globalEnv_FindClass, + .FromReflectedMethod = globalEnv_FromReflectedMethod, + .FromReflectedField = globalEnv_FromReflectedField, + .ToReflectedMethod = globalEnv_ToReflectedMethod, + .GetSuperclass = globalEnv_GetSuperclass, + .IsAssignableFrom = globalEnv_IsAssignableFrom, + .ToReflectedField = globalEnv_ToReflectedField, + .Throw = globalEnv_Throw, + .ThrowNew = globalEnv_ThrowNew, + .ExceptionOccurred = globalEnv_ExceptionOccurred, + .ExceptionDescribe = globalEnv_ExceptionDescribe, + .ExceptionClear = globalEnv_ExceptionClear, + .FatalError = globalEnv_FatalError, + .PushLocalFrame = globalEnv_PushLocalFrame, + .PopLocalFrame = globalEnv_PopLocalFrame, + .NewGlobalRef = globalEnv_NewGlobalRef, + .DeleteGlobalRef = globalEnv_DeleteGlobalRef, + .DeleteLocalRef = globalEnv_DeleteLocalRef, + .IsSameObject = globalEnv_IsSameObject, + .NewLocalRef = globalEnv_NewLocalRef, + .EnsureLocalCapacity = globalEnv_EnsureLocalCapacity, + .AllocObject = globalEnv_AllocObject, + .NewObject = globalEnv_NewObject, + .NewObjectV = NULL, + .NewObjectA = globalEnv_NewObjectA, + .GetObjectClass = globalEnv_GetObjectClass, + .IsInstanceOf = globalEnv_IsInstanceOf, + .GetMethodID = globalEnv_GetMethodID, + .CallObjectMethod = globalEnv_CallObjectMethod, + .CallObjectMethodV = NULL, + .CallObjectMethodA = globalEnv_CallObjectMethodA, + .CallBooleanMethod = globalEnv_CallBooleanMethod, + .CallBooleanMethodV = NULL, + .CallBooleanMethodA = globalEnv_CallBooleanMethodA, + .CallByteMethod = globalEnv_CallByteMethod, + .CallByteMethodV = NULL, + .CallByteMethodA = globalEnv_CallByteMethodA, + .CallCharMethod = globalEnv_CallCharMethod, + .CallCharMethodV = NULL, + .CallCharMethodA = globalEnv_CallCharMethodA, + .CallShortMethod = globalEnv_CallShortMethod, + .CallShortMethodV = NULL, + .CallShortMethodA = globalEnv_CallShortMethodA, + .CallIntMethod = globalEnv_CallIntMethod, + .CallIntMethodV = NULL, + .CallIntMethodA = globalEnv_CallIntMethodA, + .CallLongMethod = globalEnv_CallLongMethod, + .CallLongMethodV = NULL, + .CallLongMethodA = globalEnv_CallLongMethodA, + .CallFloatMethod = globalEnv_CallFloatMethod, + .CallFloatMethodV = NULL, + .CallFloatMethodA = globalEnv_CallFloatMethodA, + .CallDoubleMethod = globalEnv_CallDoubleMethod, + .CallDoubleMethodV = NULL, + .CallDoubleMethodA = globalEnv_CallDoubleMethodA, + .CallVoidMethod = globalEnv_CallVoidMethod, + .CallVoidMethodV = NULL, + .CallVoidMethodA = globalEnv_CallVoidMethodA, + .CallNonvirtualObjectMethod = globalEnv_CallNonvirtualObjectMethod, + .CallNonvirtualObjectMethodV = NULL, + .CallNonvirtualObjectMethodA = globalEnv_CallNonvirtualObjectMethodA, + .CallNonvirtualBooleanMethod = globalEnv_CallNonvirtualBooleanMethod, + .CallNonvirtualBooleanMethodV = NULL, + .CallNonvirtualBooleanMethodA = globalEnv_CallNonvirtualBooleanMethodA, + .CallNonvirtualByteMethod = globalEnv_CallNonvirtualByteMethod, + .CallNonvirtualByteMethodV = NULL, + .CallNonvirtualByteMethodA = globalEnv_CallNonvirtualByteMethodA, + .CallNonvirtualCharMethod = globalEnv_CallNonvirtualCharMethod, + .CallNonvirtualCharMethodV = NULL, + .CallNonvirtualCharMethodA = globalEnv_CallNonvirtualCharMethodA, + .CallNonvirtualShortMethod = globalEnv_CallNonvirtualShortMethod, + .CallNonvirtualShortMethodV = NULL, + .CallNonvirtualShortMethodA = globalEnv_CallNonvirtualShortMethodA, + .CallNonvirtualIntMethod = globalEnv_CallNonvirtualIntMethod, + .CallNonvirtualIntMethodV = NULL, + .CallNonvirtualIntMethodA = globalEnv_CallNonvirtualIntMethodA, + .CallNonvirtualLongMethod = globalEnv_CallNonvirtualLongMethod, + .CallNonvirtualLongMethodV = NULL, + .CallNonvirtualLongMethodA = globalEnv_CallNonvirtualLongMethodA, + .CallNonvirtualFloatMethod = globalEnv_CallNonvirtualFloatMethod, + .CallNonvirtualFloatMethodV = NULL, + .CallNonvirtualFloatMethodA = globalEnv_CallNonvirtualFloatMethodA, + .CallNonvirtualDoubleMethod = globalEnv_CallNonvirtualDoubleMethod, + .CallNonvirtualDoubleMethodV = NULL, + .CallNonvirtualDoubleMethodA = globalEnv_CallNonvirtualDoubleMethodA, + .CallNonvirtualVoidMethod = globalEnv_CallNonvirtualVoidMethod, + .CallNonvirtualVoidMethodV = NULL, + .CallNonvirtualVoidMethodA = globalEnv_CallNonvirtualVoidMethodA, + .GetFieldID = globalEnv_GetFieldID, + .GetObjectField = globalEnv_GetObjectField, + .GetBooleanField = globalEnv_GetBooleanField, + .GetByteField = globalEnv_GetByteField, + .GetCharField = globalEnv_GetCharField, + .GetShortField = globalEnv_GetShortField, + .GetIntField = globalEnv_GetIntField, + .GetLongField = globalEnv_GetLongField, + .GetFloatField = globalEnv_GetFloatField, + .GetDoubleField = globalEnv_GetDoubleField, + .SetObjectField = globalEnv_SetObjectField, + .SetBooleanField = globalEnv_SetBooleanField, + .SetByteField = globalEnv_SetByteField, + .SetCharField = globalEnv_SetCharField, + .SetShortField = globalEnv_SetShortField, + .SetIntField = globalEnv_SetIntField, + .SetLongField = globalEnv_SetLongField, + .SetFloatField = globalEnv_SetFloatField, + .SetDoubleField = globalEnv_SetDoubleField, + .GetStaticMethodID = globalEnv_GetStaticMethodID, + .CallStaticObjectMethod = globalEnv_CallStaticObjectMethod, + .CallStaticObjectMethodV = NULL, + .CallStaticObjectMethodA = globalEnv_CallStaticObjectMethodA, + .CallStaticBooleanMethod = globalEnv_CallStaticBooleanMethod, + .CallStaticBooleanMethodV = NULL, + .CallStaticBooleanMethodA = globalEnv_CallStaticBooleanMethodA, + .CallStaticByteMethod = globalEnv_CallStaticByteMethod, + .CallStaticByteMethodV = NULL, + .CallStaticByteMethodA = globalEnv_CallStaticByteMethodA, + .CallStaticCharMethod = globalEnv_CallStaticCharMethod, + .CallStaticCharMethodV = NULL, + .CallStaticCharMethodA = globalEnv_CallStaticCharMethodA, + .CallStaticShortMethod = globalEnv_CallStaticShortMethod, + .CallStaticShortMethodV = NULL, + .CallStaticShortMethodA = globalEnv_CallStaticShortMethodA, + .CallStaticIntMethod = globalEnv_CallStaticIntMethod, + .CallStaticIntMethodV = NULL, + .CallStaticIntMethodA = globalEnv_CallStaticIntMethodA, + .CallStaticLongMethod = globalEnv_CallStaticLongMethod, + .CallStaticLongMethodV = NULL, + .CallStaticLongMethodA = globalEnv_CallStaticLongMethodA, + .CallStaticFloatMethod = globalEnv_CallStaticFloatMethod, + .CallStaticFloatMethodV = NULL, + .CallStaticFloatMethodA = globalEnv_CallStaticFloatMethodA, + .CallStaticDoubleMethod = globalEnv_CallStaticDoubleMethod, + .CallStaticDoubleMethodV = NULL, + .CallStaticDoubleMethodA = globalEnv_CallStaticDoubleMethodA, + .CallStaticVoidMethod = globalEnv_CallStaticVoidMethod, + .CallStaticVoidMethodV = NULL, + .CallStaticVoidMethodA = globalEnv_CallStaticVoidMethodA, + .GetStaticFieldID = globalEnv_GetStaticFieldID, + .GetStaticObjectField = globalEnv_GetStaticObjectField, + .GetStaticBooleanField = globalEnv_GetStaticBooleanField, + .GetStaticByteField = globalEnv_GetStaticByteField, + .GetStaticCharField = globalEnv_GetStaticCharField, + .GetStaticShortField = globalEnv_GetStaticShortField, + .GetStaticIntField = globalEnv_GetStaticIntField, + .GetStaticLongField = globalEnv_GetStaticLongField, + .GetStaticFloatField = globalEnv_GetStaticFloatField, + .GetStaticDoubleField = globalEnv_GetStaticDoubleField, + .SetStaticObjectField = globalEnv_SetStaticObjectField, + .SetStaticBooleanField = globalEnv_SetStaticBooleanField, + .SetStaticByteField = globalEnv_SetStaticByteField, + .SetStaticCharField = globalEnv_SetStaticCharField, + .SetStaticShortField = globalEnv_SetStaticShortField, + .SetStaticIntField = globalEnv_SetStaticIntField, + .SetStaticLongField = globalEnv_SetStaticLongField, + .SetStaticFloatField = globalEnv_SetStaticFloatField, + .SetStaticDoubleField = globalEnv_SetStaticDoubleField, + .NewString = globalEnv_NewString, + .GetStringLength = globalEnv_GetStringLength, + .GetStringChars = globalEnv_GetStringChars, + .ReleaseStringChars = globalEnv_ReleaseStringChars, + .NewStringUTF = globalEnv_NewStringUTF, + .GetStringUTFLength = globalEnv_GetStringUTFLength, + .GetStringUTFChars = globalEnv_GetStringUTFChars, + .ReleaseStringUTFChars = globalEnv_ReleaseStringUTFChars, + .GetArrayLength = globalEnv_GetArrayLength, + .NewObjectArray = globalEnv_NewObjectArray, + .GetObjectArrayElement = globalEnv_GetObjectArrayElement, + .SetObjectArrayElement = globalEnv_SetObjectArrayElement, + .NewBooleanArray = globalEnv_NewBooleanArray, + .NewByteArray = globalEnv_NewByteArray, + .NewCharArray = globalEnv_NewCharArray, + .NewShortArray = globalEnv_NewShortArray, + .NewIntArray = globalEnv_NewIntArray, + .NewLongArray = globalEnv_NewLongArray, + .NewFloatArray = globalEnv_NewFloatArray, + .NewDoubleArray = globalEnv_NewDoubleArray, + .GetBooleanArrayElements = globalEnv_GetBooleanArrayElements, + .GetByteArrayElements = globalEnv_GetByteArrayElements, + .GetCharArrayElements = globalEnv_GetCharArrayElements, + .GetShortArrayElements = globalEnv_GetShortArrayElements, + .GetIntArrayElements = globalEnv_GetIntArrayElements, + .GetLongArrayElements = globalEnv_GetLongArrayElements, + .GetFloatArrayElements = globalEnv_GetFloatArrayElements, + .GetDoubleArrayElements = globalEnv_GetDoubleArrayElements, + .ReleaseBooleanArrayElements = globalEnv_ReleaseBooleanArrayElements, + .ReleaseByteArrayElements = globalEnv_ReleaseByteArrayElements, + .ReleaseCharArrayElements = globalEnv_ReleaseCharArrayElements, + .ReleaseShortArrayElements = globalEnv_ReleaseShortArrayElements, + .ReleaseIntArrayElements = globalEnv_ReleaseIntArrayElements, + .ReleaseLongArrayElements = globalEnv_ReleaseLongArrayElements, + .ReleaseFloatArrayElements = globalEnv_ReleaseFloatArrayElements, + .ReleaseDoubleArrayElements = globalEnv_ReleaseDoubleArrayElements, + .GetBooleanArrayRegion = globalEnv_GetBooleanArrayRegion, + .GetByteArrayRegion = globalEnv_GetByteArrayRegion, + .GetCharArrayRegion = globalEnv_GetCharArrayRegion, + .GetShortArrayRegion = globalEnv_GetShortArrayRegion, + .GetIntArrayRegion = globalEnv_GetIntArrayRegion, + .GetLongArrayRegion = globalEnv_GetLongArrayRegion, + .GetFloatArrayRegion = globalEnv_GetFloatArrayRegion, + .GetDoubleArrayRegion = globalEnv_GetDoubleArrayRegion, + .SetBooleanArrayRegion = globalEnv_SetBooleanArrayRegion, + .SetByteArrayRegion = globalEnv_SetByteArrayRegion, + .SetCharArrayRegion = globalEnv_SetCharArrayRegion, + .SetShortArrayRegion = globalEnv_SetShortArrayRegion, + .SetIntArrayRegion = globalEnv_SetIntArrayRegion, + .SetLongArrayRegion = globalEnv_SetLongArrayRegion, + .SetFloatArrayRegion = globalEnv_SetFloatArrayRegion, + .SetDoubleArrayRegion = globalEnv_SetDoubleArrayRegion, + .RegisterNatives = globalEnv_RegisterNatives, + .UnregisterNatives = globalEnv_UnregisterNatives, + .MonitorEnter = globalEnv_MonitorEnter, + .MonitorExit = globalEnv_MonitorExit, + .GetJavaVM = globalEnv_GetJavaVM, + .GetStringRegion = globalEnv_GetStringRegion, + .GetStringUTFRegion = globalEnv_GetStringUTFRegion, + .GetPrimitiveArrayCritical = globalEnv_GetPrimitiveArrayCritical, + .ReleasePrimitiveArrayCritical = globalEnv_ReleasePrimitiveArrayCritical, + .GetStringCritical = globalEnv_GetStringCritical, + .ReleaseStringCritical = globalEnv_ReleaseStringCritical, + .NewWeakGlobalRef = globalEnv_NewWeakGlobalRef, + .DeleteWeakGlobalRef = globalEnv_DeleteWeakGlobalRef, + .ExceptionCheck = globalEnv_ExceptionCheck, + .NewDirectByteBuffer = globalEnv_NewDirectByteBuffer, + .GetDirectBufferAddress = globalEnv_GetDirectBufferAddress, + .GetDirectBufferCapacity = globalEnv_GetDirectBufferCapacity, + .GetObjectRefType = globalEnv_GetObjectRefType, +}; +FFI_PLUGIN_EXPORT +GlobalJniEnvStruct* GetGlobalEnv() { + if (jni->jvm == NULL) { + return NULL; + } + return &globalJniEnv; +} diff --git a/pkgs/jni/src/third_party/global_jni_env.h b/pkgs/jni/src/third_party/global_jni_env.h new file mode 100644 index 000000000..562b1bf64 --- /dev/null +++ b/pkgs/jni/src/third_party/global_jni_env.h @@ -0,0 +1,434 @@ +// Auto generated file. Do not edit. + +// This is generated from JNI header in Android NDK. License for the same is +// provided below. + +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * JNI specification, as defined by Sun: + * http://java.sun.com/javase/6/docs/technotes/guides/jni/spec/jniTOC.html + * + * Everything here is expected to be VM-neutral. + */ + +#include +#include "../dartjni.h" + +typedef struct GlobalJniEnvStruct { + void* reserved0; + void* reserved1; + void* reserved2; + void* reserved3; + JniResult (*GetVersion)(); + JniClassLookupResult (*DefineClass)(char* name, + jobject loader, + jbyte* buf, + jsize bufLen); + JniClassLookupResult (*FindClass)(char* name); + JniPointerResult (*FromReflectedMethod)(jobject method); + JniPointerResult (*FromReflectedField)(jobject field); + JniResult (*ToReflectedMethod)(jclass cls, + jmethodID methodId, + jboolean isStatic); + JniClassLookupResult (*GetSuperclass)(jclass clazz); + JniResult (*IsAssignableFrom)(jclass clazz1, jclass clazz2); + JniResult (*ToReflectedField)(jclass cls, + jfieldID fieldID, + jboolean isStatic); + JniResult (*Throw)(jthrowable obj); + JniResult (*ThrowNew)(jclass clazz, char* message); + JniResult (*ExceptionOccurred)(); + jthrowable (*ExceptionDescribe)(); + jthrowable (*ExceptionClear)(); + jthrowable (*FatalError)(char* msg); + JniResult (*PushLocalFrame)(jint capacity); + JniResult (*PopLocalFrame)(jobject result); + JniResult (*NewGlobalRef)(jobject obj); + jthrowable (*DeleteGlobalRef)(jobject globalRef); + jthrowable (*DeleteLocalRef)(jobject localRef); + JniResult (*IsSameObject)(jobject ref1, jobject ref2); + JniResult (*NewLocalRef)(jobject obj); + JniResult (*EnsureLocalCapacity)(jint capacity); + JniResult (*AllocObject)(jclass clazz); + JniResult (*NewObject)(jclass clazz, jmethodID methodID); + JniResult (*NewObjectV)(jclass, jmethodID, void*); + JniResult (*NewObjectA)(jclass clazz, jmethodID methodID, jvalue* args); + JniClassLookupResult (*GetObjectClass)(jobject obj); + JniResult (*IsInstanceOf)(jobject obj, jclass clazz); + JniPointerResult (*GetMethodID)(jclass clazz, char* name, char* sig); + JniResult (*CallObjectMethod)(jobject obj, jmethodID methodID); + JniResult (*CallObjectMethodV)(jobject, jmethodID, void*); + JniResult (*CallObjectMethodA)(jobject obj, jmethodID methodID, jvalue* args); + JniResult (*CallBooleanMethod)(jobject obj, jmethodID methodID); + JniResult (*CallBooleanMethodV)(jobject, jmethodID, void*); + JniResult (*CallBooleanMethodA)(jobject obj, + jmethodID methodId, + jvalue* args); + JniResult (*CallByteMethod)(jobject obj, jmethodID methodID); + JniResult (*CallByteMethodV)(jobject, jmethodID, void*); + JniResult (*CallByteMethodA)(jobject obj, jmethodID methodID, jvalue* args); + JniResult (*CallCharMethod)(jobject obj, jmethodID methodID); + JniResult (*CallCharMethodV)(jobject, jmethodID, void*); + JniResult (*CallCharMethodA)(jobject obj, jmethodID methodID, jvalue* args); + JniResult (*CallShortMethod)(jobject obj, jmethodID methodID); + JniResult (*CallShortMethodV)(jobject, jmethodID, void*); + JniResult (*CallShortMethodA)(jobject obj, jmethodID methodID, jvalue* args); + JniResult (*CallIntMethod)(jobject obj, jmethodID methodID); + JniResult (*CallIntMethodV)(jobject, jmethodID, void*); + JniResult (*CallIntMethodA)(jobject obj, jmethodID methodID, jvalue* args); + JniResult (*CallLongMethod)(jobject obj, jmethodID methodID); + JniResult (*CallLongMethodV)(jobject, jmethodID, void*); + JniResult (*CallLongMethodA)(jobject obj, jmethodID methodID, jvalue* args); + JniResult (*CallFloatMethod)(jobject obj, jmethodID methodID); + JniResult (*CallFloatMethodV)(jobject, jmethodID, void*); + JniResult (*CallFloatMethodA)(jobject obj, jmethodID methodID, jvalue* args); + JniResult (*CallDoubleMethod)(jobject obj, jmethodID methodID); + JniResult (*CallDoubleMethodV)(jobject, jmethodID, void*); + JniResult (*CallDoubleMethodA)(jobject obj, jmethodID methodID, jvalue* args); + jthrowable (*CallVoidMethod)(jobject obj, jmethodID methodID); + jthrowable (*CallVoidMethodV)(jobject, jmethodID, void*); + jthrowable (*CallVoidMethodA)(jobject obj, jmethodID methodID, jvalue* args); + JniResult (*CallNonvirtualObjectMethod)(jobject obj, + jclass clazz, + jmethodID methodID); + JniResult (*CallNonvirtualObjectMethodV)(jobject, jclass, jmethodID, void*); + JniResult (*CallNonvirtualObjectMethodA)(jobject obj, + jclass clazz, + jmethodID methodID, + jvalue* args); + JniResult (*CallNonvirtualBooleanMethod)(jobject obj, + jclass clazz, + jmethodID methodID); + JniResult (*CallNonvirtualBooleanMethodV)(jobject, jclass, jmethodID, void*); + JniResult (*CallNonvirtualBooleanMethodA)(jobject obj, + jclass clazz, + jmethodID methodID, + jvalue* args); + JniResult (*CallNonvirtualByteMethod)(jobject obj, + jclass clazz, + jmethodID methodID); + JniResult (*CallNonvirtualByteMethodV)(jobject, jclass, jmethodID, void*); + JniResult (*CallNonvirtualByteMethodA)(jobject obj, + jclass clazz, + jmethodID methodID, + jvalue* args); + JniResult (*CallNonvirtualCharMethod)(jobject obj, + jclass clazz, + jmethodID methodID); + JniResult (*CallNonvirtualCharMethodV)(jobject, jclass, jmethodID, void*); + JniResult (*CallNonvirtualCharMethodA)(jobject obj, + jclass clazz, + jmethodID methodID, + jvalue* args); + JniResult (*CallNonvirtualShortMethod)(jobject obj, + jclass clazz, + jmethodID methodID); + JniResult (*CallNonvirtualShortMethodV)(jobject, jclass, jmethodID, void*); + JniResult (*CallNonvirtualShortMethodA)(jobject obj, + jclass clazz, + jmethodID methodID, + jvalue* args); + JniResult (*CallNonvirtualIntMethod)(jobject obj, + jclass clazz, + jmethodID methodID); + JniResult (*CallNonvirtualIntMethodV)(jobject, jclass, jmethodID, void*); + JniResult (*CallNonvirtualIntMethodA)(jobject obj, + jclass clazz, + jmethodID methodID, + jvalue* args); + JniResult (*CallNonvirtualLongMethod)(jobject obj, + jclass clazz, + jmethodID methodID); + JniResult (*CallNonvirtualLongMethodV)(jobject, jclass, jmethodID, void*); + JniResult (*CallNonvirtualLongMethodA)(jobject obj, + jclass clazz, + jmethodID methodID, + jvalue* args); + JniResult (*CallNonvirtualFloatMethod)(jobject obj, + jclass clazz, + jmethodID methodID); + JniResult (*CallNonvirtualFloatMethodV)(jobject, jclass, jmethodID, void*); + JniResult (*CallNonvirtualFloatMethodA)(jobject obj, + jclass clazz, + jmethodID methodID, + jvalue* args); + JniResult (*CallNonvirtualDoubleMethod)(jobject obj, + jclass clazz, + jmethodID methodID); + JniResult (*CallNonvirtualDoubleMethodV)(jobject, jclass, jmethodID, void*); + JniResult (*CallNonvirtualDoubleMethodA)(jobject obj, + jclass clazz, + jmethodID methodID, + jvalue* args); + jthrowable (*CallNonvirtualVoidMethod)(jobject obj, + jclass clazz, + jmethodID methodID); + jthrowable (*CallNonvirtualVoidMethodV)(jobject, jclass, jmethodID, void*); + jthrowable (*CallNonvirtualVoidMethodA)(jobject obj, + jclass clazz, + jmethodID methodID, + jvalue* args); + JniPointerResult (*GetFieldID)(jclass clazz, char* name, char* sig); + JniResult (*GetObjectField)(jobject obj, jfieldID fieldID); + JniResult (*GetBooleanField)(jobject obj, jfieldID fieldID); + JniResult (*GetByteField)(jobject obj, jfieldID fieldID); + JniResult (*GetCharField)(jobject obj, jfieldID fieldID); + JniResult (*GetShortField)(jobject obj, jfieldID fieldID); + JniResult (*GetIntField)(jobject obj, jfieldID fieldID); + JniResult (*GetLongField)(jobject obj, jfieldID fieldID); + JniResult (*GetFloatField)(jobject obj, jfieldID fieldID); + JniResult (*GetDoubleField)(jobject obj, jfieldID fieldID); + jthrowable (*SetObjectField)(jobject obj, jfieldID fieldID, jobject val); + jthrowable (*SetBooleanField)(jobject obj, jfieldID fieldID, jboolean val); + jthrowable (*SetByteField)(jobject obj, jfieldID fieldID, jbyte val); + jthrowable (*SetCharField)(jobject obj, jfieldID fieldID, jchar val); + jthrowable (*SetShortField)(jobject obj, jfieldID fieldID, jshort val); + jthrowable (*SetIntField)(jobject obj, jfieldID fieldID, jint val); + jthrowable (*SetLongField)(jobject obj, jfieldID fieldID, jlong val); + jthrowable (*SetFloatField)(jobject obj, jfieldID fieldID, jfloat val); + jthrowable (*SetDoubleField)(jobject obj, jfieldID fieldID, jdouble val); + JniPointerResult (*GetStaticMethodID)(jclass clazz, char* name, char* sig); + JniResult (*CallStaticObjectMethod)(jclass clazz, jmethodID methodID); + JniResult (*CallStaticObjectMethodV)(jclass, jmethodID, void*); + JniResult (*CallStaticObjectMethodA)(jclass clazz, + jmethodID methodID, + jvalue* args); + JniResult (*CallStaticBooleanMethod)(jclass clazz, jmethodID methodID); + JniResult (*CallStaticBooleanMethodV)(jclass, jmethodID, void*); + JniResult (*CallStaticBooleanMethodA)(jclass clazz, + jmethodID methodID, + jvalue* args); + JniResult (*CallStaticByteMethod)(jclass clazz, jmethodID methodID); + JniResult (*CallStaticByteMethodV)(jclass, jmethodID, void*); + JniResult (*CallStaticByteMethodA)(jclass clazz, + jmethodID methodID, + jvalue* args); + JniResult (*CallStaticCharMethod)(jclass clazz, jmethodID methodID); + JniResult (*CallStaticCharMethodV)(jclass, jmethodID, void*); + JniResult (*CallStaticCharMethodA)(jclass clazz, + jmethodID methodID, + jvalue* args); + JniResult (*CallStaticShortMethod)(jclass clazz, jmethodID methodID); + JniResult (*CallStaticShortMethodV)(jclass, jmethodID, void*); + JniResult (*CallStaticShortMethodA)(jclass clazz, + jmethodID methodID, + jvalue* args); + JniResult (*CallStaticIntMethod)(jclass clazz, jmethodID methodID); + JniResult (*CallStaticIntMethodV)(jclass, jmethodID, void*); + JniResult (*CallStaticIntMethodA)(jclass clazz, + jmethodID methodID, + jvalue* args); + JniResult (*CallStaticLongMethod)(jclass clazz, jmethodID methodID); + JniResult (*CallStaticLongMethodV)(jclass, jmethodID, void*); + JniResult (*CallStaticLongMethodA)(jclass clazz, + jmethodID methodID, + jvalue* args); + JniResult (*CallStaticFloatMethod)(jclass clazz, jmethodID methodID); + JniResult (*CallStaticFloatMethodV)(jclass, jmethodID, void*); + JniResult (*CallStaticFloatMethodA)(jclass clazz, + jmethodID methodID, + jvalue* args); + JniResult (*CallStaticDoubleMethod)(jclass clazz, jmethodID methodID); + JniResult (*CallStaticDoubleMethodV)(jclass, jmethodID, void*); + JniResult (*CallStaticDoubleMethodA)(jclass clazz, + jmethodID methodID, + jvalue* args); + jthrowable (*CallStaticVoidMethod)(jclass clazz, jmethodID methodID); + jthrowable (*CallStaticVoidMethodV)(jclass, jmethodID, void*); + jthrowable (*CallStaticVoidMethodA)(jclass clazz, + jmethodID methodID, + jvalue* args); + JniPointerResult (*GetStaticFieldID)(jclass clazz, char* name, char* sig); + JniResult (*GetStaticObjectField)(jclass clazz, jfieldID fieldID); + JniResult (*GetStaticBooleanField)(jclass clazz, jfieldID fieldID); + JniResult (*GetStaticByteField)(jclass clazz, jfieldID fieldID); + JniResult (*GetStaticCharField)(jclass clazz, jfieldID fieldID); + JniResult (*GetStaticShortField)(jclass clazz, jfieldID fieldID); + JniResult (*GetStaticIntField)(jclass clazz, jfieldID fieldID); + JniResult (*GetStaticLongField)(jclass clazz, jfieldID fieldID); + JniResult (*GetStaticFloatField)(jclass clazz, jfieldID fieldID); + JniResult (*GetStaticDoubleField)(jclass clazz, jfieldID fieldID); + jthrowable (*SetStaticObjectField)(jclass clazz, + jfieldID fieldID, + jobject val); + jthrowable (*SetStaticBooleanField)(jclass clazz, + jfieldID fieldID, + jboolean val); + jthrowable (*SetStaticByteField)(jclass clazz, jfieldID fieldID, jbyte val); + jthrowable (*SetStaticCharField)(jclass clazz, jfieldID fieldID, jchar val); + jthrowable (*SetStaticShortField)(jclass clazz, jfieldID fieldID, jshort val); + jthrowable (*SetStaticIntField)(jclass clazz, jfieldID fieldID, jint val); + jthrowable (*SetStaticLongField)(jclass clazz, jfieldID fieldID, jlong val); + jthrowable (*SetStaticFloatField)(jclass clazz, jfieldID fieldID, jfloat val); + jthrowable (*SetStaticDoubleField)(jclass clazz, + jfieldID fieldID, + jdouble val); + JniResult (*NewString)(jchar* unicodeChars, jsize len); + JniResult (*GetStringLength)(jstring string); + JniPointerResult (*GetStringChars)(jstring string, jboolean* isCopy); + jthrowable (*ReleaseStringChars)(jstring string, jchar* isCopy); + JniResult (*NewStringUTF)(char* bytes); + JniResult (*GetStringUTFLength)(jstring string); + JniPointerResult (*GetStringUTFChars)(jstring string, jboolean* isCopy); + jthrowable (*ReleaseStringUTFChars)(jstring string, char* utf); + JniResult (*GetArrayLength)(jarray array); + JniResult (*NewObjectArray)(jsize length, + jclass elementClass, + jobject initialElement); + JniResult (*GetObjectArrayElement)(jobjectArray array, jsize index); + jthrowable (*SetObjectArrayElement)(jobjectArray array, + jsize index, + jobject val); + JniResult (*NewBooleanArray)(jsize length); + JniResult (*NewByteArray)(jsize length); + JniResult (*NewCharArray)(jsize length); + JniResult (*NewShortArray)(jsize length); + JniResult (*NewIntArray)(jsize length); + JniResult (*NewLongArray)(jsize length); + JniResult (*NewFloatArray)(jsize length); + JniResult (*NewDoubleArray)(jsize length); + JniPointerResult (*GetBooleanArrayElements)(jbooleanArray array, + jboolean* isCopy); + JniPointerResult (*GetByteArrayElements)(jbyteArray array, jboolean* isCopy); + JniPointerResult (*GetCharArrayElements)(jcharArray array, jboolean* isCopy); + JniPointerResult (*GetShortArrayElements)(jshortArray array, + jboolean* isCopy); + JniPointerResult (*GetIntArrayElements)(jintArray array, jboolean* isCopy); + JniPointerResult (*GetLongArrayElements)(jlongArray array, jboolean* isCopy); + JniPointerResult (*GetFloatArrayElements)(jfloatArray array, + jboolean* isCopy); + JniPointerResult (*GetDoubleArrayElements)(jdoubleArray array, + jboolean* isCopy); + jthrowable (*ReleaseBooleanArrayElements)(jbooleanArray array, + jboolean* elems, + jint mode); + jthrowable (*ReleaseByteArrayElements)(jbyteArray array, + jbyte* elems, + jint mode); + jthrowable (*ReleaseCharArrayElements)(jcharArray array, + jchar* elems, + jint mode); + jthrowable (*ReleaseShortArrayElements)(jshortArray array, + jshort* elems, + jint mode); + jthrowable (*ReleaseIntArrayElements)(jintArray array, + jint* elems, + jint mode); + jthrowable (*ReleaseLongArrayElements)(jlongArray array, + jlong* elems, + jint mode); + jthrowable (*ReleaseFloatArrayElements)(jfloatArray array, + jfloat* elems, + jint mode); + jthrowable (*ReleaseDoubleArrayElements)(jdoubleArray array, + jdouble* elems, + jint mode); + jthrowable (*GetBooleanArrayRegion)(jbooleanArray array, + jsize start, + jsize len, + jboolean* buf); + jthrowable (*GetByteArrayRegion)(jbyteArray array, + jsize start, + jsize len, + jbyte* buf); + jthrowable (*GetCharArrayRegion)(jcharArray array, + jsize start, + jsize len, + jchar* buf); + jthrowable (*GetShortArrayRegion)(jshortArray array, + jsize start, + jsize len, + jshort* buf); + jthrowable (*GetIntArrayRegion)(jintArray array, + jsize start, + jsize len, + jint* buf); + jthrowable (*GetLongArrayRegion)(jlongArray array, + jsize start, + jsize len, + jlong* buf); + jthrowable (*GetFloatArrayRegion)(jfloatArray array, + jsize start, + jsize len, + jfloat* buf); + jthrowable (*GetDoubleArrayRegion)(jdoubleArray array, + jsize start, + jsize len, + jdouble* buf); + jthrowable (*SetBooleanArrayRegion)(jbooleanArray array, + jsize start, + jsize len, + jboolean* buf); + jthrowable (*SetByteArrayRegion)(jbyteArray array, + jsize start, + jsize len, + jbyte* buf); + jthrowable (*SetCharArrayRegion)(jcharArray array, + jsize start, + jsize len, + jchar* buf); + jthrowable (*SetShortArrayRegion)(jshortArray array, + jsize start, + jsize len, + jshort* buf); + jthrowable (*SetIntArrayRegion)(jintArray array, + jsize start, + jsize len, + jint* buf); + jthrowable (*SetLongArrayRegion)(jlongArray array, + jsize start, + jsize len, + jlong* buf); + jthrowable (*SetFloatArrayRegion)(jfloatArray array, + jsize start, + jsize len, + jfloat* buf); + jthrowable (*SetDoubleArrayRegion)(jdoubleArray array, + jsize start, + jsize len, + jdouble* buf); + JniResult (*RegisterNatives)(jclass clazz, + JNINativeMethod* methods, + jint nMethods); + JniResult (*UnregisterNatives)(jclass clazz); + JniResult (*MonitorEnter)(jobject obj); + JniResult (*MonitorExit)(jobject obj); + JniResult (*GetJavaVM)(JavaVM** vm); + jthrowable (*GetStringRegion)(jstring str, + jsize start, + jsize len, + jchar* buf); + jthrowable (*GetStringUTFRegion)(jstring str, + jsize start, + jsize len, + char* buf); + JniPointerResult (*GetPrimitiveArrayCritical)(jarray array, jboolean* isCopy); + jthrowable (*ReleasePrimitiveArrayCritical)(jarray array, + void* carray, + jint mode); + JniPointerResult (*GetStringCritical)(jstring str, jboolean* isCopy); + jthrowable (*ReleaseStringCritical)(jstring str, jchar* carray); + JniResult (*NewWeakGlobalRef)(jobject obj); + jthrowable (*DeleteWeakGlobalRef)(jweak obj); + JniResult (*ExceptionCheck)(); + JniResult (*NewDirectByteBuffer)(void* address, jlong capacity); + JniPointerResult (*GetDirectBufferAddress)(jobject buf); + JniResult (*GetDirectBufferCapacity)(jobject buf); + JniResult (*GetObjectRefType)(jobject obj); +} GlobalJniEnvStruct; +FFI_PLUGIN_EXPORT GlobalJniEnvStruct* GetGlobalEnv(); diff --git a/pkgs/jni/test/boxed_test.dart b/pkgs/jni/test/boxed_test.dart new file mode 100644 index 000000000..261b1accc --- /dev/null +++ b/pkgs/jni/test/boxed_test.dart @@ -0,0 +1,146 @@ +// Copyright (c) 2023, 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. + +import 'dart:io'; + +import 'package:jni/jni.dart'; +import 'package:test/test.dart'; + +import 'test_util/test_util.dart'; + +void main() { + // Don't forget to initialize JNI. + if (!Platform.isAndroid) { + checkDylibIsUpToDate(); + Jni.spawnIfNotExists(dylibDir: "build/jni_libs", jvmOptions: ["-Xmx128m"]); + } + run(testRunner: test); +} + +void run({required TestRunnerCallback testRunner}) { + testRunner('JByte', () { + const val = 1 << 5; + using((arena) { + expect(JByte(val).byteValue(releaseOriginal: true), val); + expect((-val).toJByte().byteValue(releaseOriginal: true), -val); + }); + }); + testRunner('JCharacter', () { + const val = 1 << 5; + using((arena) { + expect(JCharacter(val).charValue(releaseOriginal: true), val); + expect(JCharacter(0).charValue(releaseOriginal: true), 0); + }); + }); + testRunner('JShort', () { + const val = 1 << 10; + using((arena) { + expect(JShort(val).shortValue(releaseOriginal: true), val); + expect((-val).toJShort().shortValue(releaseOriginal: true), -val); + }); + }); + testRunner('JInteger', () { + const val = 1 << 20; + using((arena) { + expect(JInteger(val).intValue(releaseOriginal: true), val); + expect((-val).toJInteger().intValue(releaseOriginal: true), -val); + }); + }); + testRunner('JLong', () { + const val = 1 << 40; + using((arena) { + expect(JLong(val).longValue(releaseOriginal: true), val); + expect((-val).toJLong().longValue(releaseOriginal: true), -val); + }); + }); + testRunner('JFloat', () { + const val = 3.14; + const eps = 1e-6; + using((arena) { + expect(JFloat(val).floatValue(releaseOriginal: true), closeTo(val, eps)); + expect((-val).toJFloat().floatValue(releaseOriginal: true), + closeTo(-val, eps)); + }); + }); + testRunner('JDouble', () { + const val = 3.14; + const eps = 1e-9; + using((arena) { + expect( + JDouble(val).doubleValue(releaseOriginal: true), closeTo(val, eps)); + expect((-val).toJDouble().doubleValue(releaseOriginal: true), + closeTo(-val, eps)); + }); + }); + testRunner('JBoolean', () { + using((arena) { + expect(JBoolean(false).booleanValue(releaseOriginal: true), false); + expect(JBoolean(true).booleanValue(releaseOriginal: true), true); + }); + }); + testRunner('JByte.\$type hashCode and ==', () { + using((arena) { + final a = JByte(1)..releasedBy(arena); + final b = JByte(2)..releasedBy(arena); + expect(a.$type, b.$type); + expect(a.$type.hashCode, b.$type.hashCode); + }); + }); + testRunner('JCharacter.\$type hashCode and ==', () { + using((arena) { + final a = JCharacter(1)..releasedBy(arena); + final b = JCharacter(2)..releasedBy(arena); + expect(a.$type, b.$type); + expect(a.$type.hashCode, b.$type.hashCode); + }); + }); + testRunner('JShort.\$type hashCode and ==', () { + using((arena) { + final a = JShort(1)..releasedBy(arena); + final b = JShort(2)..releasedBy(arena); + expect(a.$type, b.$type); + expect(a.$type.hashCode, b.$type.hashCode); + }); + }); + testRunner('JInteger.\$type hashCode and ==', () { + using((arena) { + final a = JInteger(1)..releasedBy(arena); + final b = JInteger(2)..releasedBy(arena); + expect(a.$type, b.$type); + expect(a.$type.hashCode, b.$type.hashCode); + }); + }); + testRunner('JLong.\$type hashCode and ==', () { + using((arena) { + final a = JLong(1)..releasedBy(arena); + final b = JLong(2)..releasedBy(arena); + expect(a.$type, b.$type); + expect(a.$type.hashCode, b.$type.hashCode); + }); + }); + testRunner('JFloat.\$type hashCode and ==', () { + using((arena) { + final a = JFloat(1.0)..releasedBy(arena); + final b = JFloat(2.0)..releasedBy(arena); + expect(a.$type, b.$type); + expect(a.$type.hashCode, b.$type.hashCode); + }); + }); + testRunner('JDouble.\$type hashCode and ==', () { + using((arena) { + final a = JDouble(1.0)..releasedBy(arena); + final b = JDouble(2.0)..releasedBy(arena); + expect(a.$type, b.$type); + expect(a.$type.hashCode, b.$type.hashCode); + }); + }); + testRunner('JBoolean.\$type hashCode and ==', () { + using((arena) { + final a = JBoolean(true)..releasedBy(arena); + final b = JBoolean(false)..releasedBy(arena); + expect(a.$type, b.$type); + expect(a.$type.hashCode, b.$type.hashCode); + }); + }); +} diff --git a/pkgs/jni/test/exception_test.dart b/pkgs/jni/test/exception_test.dart new file mode 100644 index 000000000..42d229764 --- /dev/null +++ b/pkgs/jni/test/exception_test.dart @@ -0,0 +1,72 @@ +// 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. + +import 'dart:io'; + +import 'package:test/test.dart'; +import 'package:jni/jni.dart'; + +import 'test_util/test_util.dart'; + +void main() { + if (!Platform.isAndroid) { + checkDylibIsUpToDate(); + bool caught = false; + try { + // If library does not exist, a helpful error should be thrown. + // we can't test this directly because `test` schedules functions + // asynchronously. + Jni.spawn(dylibDir: "wrong_dir"); + } on HelperNotFoundError catch (_) { + // stderr.write("\n$_\n"); + Jni.spawnIfNotExists( + dylibDir: "build/jni_libs", jvmOptions: ["-Xmx128m"]); + caught = true; + } on JniVmExistsError { + stderr.writeln('cannot verify: HelperNotFoundError thrown'); + } + if (!caught) { + throw "Expected HelperNotFoundException\n" + "Read exception_test.dart for details."; + } + } + run(testRunner: test); +} + +void run({required TestRunnerCallback testRunner}) { + testRunner("double free throws exception", () { + final r = Jni.newInstance("java/util/Random", "()V", []); + r.release(); + expect(r.release, throwsA(isA())); + }); + + testRunner("Use after free throws exception", () { + final r = Jni.newInstance("java/util/Random", "()V", []); + r.release(); + expect(() => r.callMethodByName("nextInt", "(I)I", [JValueInt(256)]), + throwsA(isA())); + }); + + testRunner("void fieldType throws exception", () { + final r = Jni.newInstance("java/util/Random", "()V", []); + expect(() => r.getField(nullptr, JniCallType.voidType), + throwsArgumentError); + expect(() => r.getStaticField(nullptr, JniCallType.voidType), + throwsArgumentError); + }); + + testRunner("Wrong callType throws error", () { + final r = Jni.newInstance("java/util/Random", "()V", []); + expect( + () => r.callMethodByName( + "nextInt", "(I)I", [JValueInt(256)], JniCallType.doubleType), + throwsA(isA())); + }); + + testRunner("An exception in JNI throws JniException in Dart", () { + final r = Jni.newInstance("java/util/Random", "()V", []); + expect(() => r.callMethodByName("nextInt", "(I)I", [JValueInt(-1)]), + throwsA(isA())); + }); +} diff --git a/pkgs/jni/test/global_env_test.dart b/pkgs/jni/test/global_env_test.dart new file mode 100644 index 000000000..a5588cd96 --- /dev/null +++ b/pkgs/jni/test/global_env_test.dart @@ -0,0 +1,215 @@ +// 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. + +import 'dart:io'; + +import 'package:ffi/ffi.dart'; +import 'package:jni/jni.dart'; +import 'package:jni/src/jvalues.dart'; +import 'package:test/test.dart'; + +import 'test_util/test_util.dart'; + +const maxLongInJava = 9223372036854775807; + +void main() { + // Running on Android through flutter, this plugin + // will bind to Android runtime's JVM. + // On other platforms eg Flutter desktop or Dart standalone + // You need to manually create a JVM at beginning. + // + // On flutter desktop, the C wrappers are bundled, and helperPath param + // is not required. + // + // On dart standalone, however, there's no way to bundle the wrappers. + // You have to manually pass the path to the `dartjni` dynamic library. + + if (!Platform.isAndroid) { + checkDylibIsUpToDate(); + Jni.spawnIfNotExists(dylibDir: "build/jni_libs", jvmOptions: ["-Xmx128m"]); + } + run(testRunner: test); +} + +// We are factoring these tests into a run method which allows us to run same +// tests with different environments. Eg: standalone and integration tests. +void run({required TestRunnerCallback testRunner}) { + // Tests in this file demonstrate how to use `GlobalJniEnv`, a thin + // abstraction over JNIEnv in JNI C API. This can be used from multiple + // threads, and converts all returned object references to global references, + // so that you don't need to worry about whether your Dart code will be + // scheduled on another thread. + // + // GlobalJniEnv wraps all methods of JNIEnv (UpperCamelCase, reflecting the + // original name of the method) and provides few more extension methods + // (lowerCamelCase). + // + // For examples of a higher level API, see `jni_object_tests.dart`. + final env = Jni.env; + testRunner('initDLApi', () { + Jni.initDLApi(); + }); + + testRunner('get JNI Version', () { + expect(Jni.env.GetVersion(), isNot(equals(0))); + }); + + testRunner( + 'Manually lookup & call Integer.toHexString', + () => using((arena) { + // Method names on JniEnv* from C JNI API are capitalized + // like in original, while other extension methods + // follow Dart naming conventions. + final integerClass = + env.FindClass("java/lang/Integer".toNativeChars(arena)); + // Refer JNI spec on how to construct method signatures + // Passing wrong signature leads to a segfault + final hexMethod = env.GetStaticMethodID( + integerClass, + "toHexString".toNativeChars(arena), + "(I)Ljava/lang/String;".toNativeChars(arena)); + + for (var i in [1, 80, 13, 76, 11344]) { + // if your argument is int, bool, or JObject (`Pointer`) + // it can be directly placed in the list. To convert into different primitive + // types, use JValue wrappers. + final jres = env.CallStaticObjectMethodA(integerClass, hexMethod, + Jni.jvalues([JValueInt(i)], allocator: arena)); + + // use asDartString extension method on Pointer + // to convert a String jobject result to string + final res = env.toDartString(jres); + expect(res, equals(i.toRadixString(16))); + + // Any object or class result from java is a local reference + // and needs to be deleted explicitly. + // Note that method and field IDs aren't local references. + // But they are valid only until a reference to corresponding + // java class exists. + env.DeleteGlobalRef(jres); + } + env.DeleteGlobalRef(integerClass); + })); + + testRunner("asJString extension method", () { + const str = "QWERTY QWERTY"; + // convenience method that wraps + // converting dart string to native string, + // instantiating java string, and freeing the native string + final jstr = env.toJStringPtr(str); + expect(str, equals(env.toDartString(jstr))); + env.DeleteGlobalRef(jstr); + }); + + testRunner( + 'GlobalJniEnv should catch exceptions', + () => using((arena) { + final integerClass = + env.FindClass("java/lang/Integer".toNativeChars(arena)); + final parseIntMethod = env.GetStaticMethodID( + integerClass, + "parseInt".toNativeChars(arena), + "(Ljava/lang/String;)I".toNativeChars(arena)); + final args = JValueArgs(["hello"], arena); + expect( + () => env.CallStaticIntMethodA( + integerClass, parseIntMethod, args.values), + throwsA(isA())); + })); + + testRunner( + "Convert back & forth between Dart & Java strings (UTF-8)", + () => using((arena) { + const str = "ABCD EFGH"; + final jstr = env.NewStringUTF(str.toNativeChars(arena)); + final jchars = env.GetStringUTFChars(jstr, nullptr); + final jlen = env.GetStringUTFLength(jstr); + final dstr = jchars.toDartString(length: jlen); + env.ReleaseStringUTFChars(jstr, jchars); + expect(str, equals(dstr)); + env.DeleteGlobalRef(jstr); + })); + + testRunner( + "Convert back & forth between Dart & Java strings (UTF-16)", + () => using((arena) { + const str = "ABCD EFGH"; + final jstr = env.NewString(str.toNativeUtf16().cast(), str.length); + final jchars = env.GetStringChars(jstr, nullptr); + final jlen = env.GetStringLength(jstr); + final dstr = jchars.cast().toDartString(length: jlen); + env.ReleaseStringChars(jstr, jchars); + expect(str, equals(dstr)); + env.DeleteGlobalRef(jstr); + })); + + testRunner( + "Print something from Java", + () => using((arena) { + final system = + env.FindClass("java/lang/System".toNativeChars(arena)); + final field = env.GetStaticFieldID( + system, + "out".toNativeChars(arena), + "Ljava/io/PrintStream;".toNativeChars(arena)); + final out = env.GetStaticObjectField(system, field); + final printStream = env.GetObjectClass(out); + final println = env.GetMethodID( + printStream, + "println".toNativeChars(arena), + "(Ljava/lang/String;)V".toNativeChars(arena)); + const str = "\nHello World from JNI!"; + final jstr = env.toJStringPtr(str); + env.CallVoidMethodA(out, println, Jni.jvalues([jstr])); + env.deleteAllRefs([system, printStream, jstr]); + })); + testRunner( + 'Env create reference methods should retain their default behavior', () { + final systemOut = Jni.retrieveStaticField( + "java/lang/System", "out", "Ljava/io/PrintStream;"); + var refType = env.GetObjectRefType(systemOut); + expect(refType, equals(JObjectRefType.JNIGlobalRefType)); + final localRef = env.NewLocalRef(systemOut); + refType = env.GetObjectRefType(localRef); + expect(refType, equals(JObjectRefType.JNILocalRefType)); + final weakRef = env.NewWeakGlobalRef(systemOut); + refType = env.GetObjectRefType(weakRef); + expect(refType, equals(JObjectRefType.JNIWeakGlobalRefType)); + final globalRef = env.NewGlobalRef(localRef); + refType = env.GetObjectRefType(globalRef); + expect(refType, equals(JObjectRefType.JNIGlobalRefType)); + env.DeleteGlobalRef(globalRef); + env.DeleteWeakGlobalRef(weakRef); + env.DeleteLocalRef(localRef); + env.DeleteGlobalRef(systemOut); + }); + testRunner('long methods return long int without loss of precision', () { + using((arena) { + final longClass = env.FindClass("java/lang/Long".toNativeChars(arena)); + final maxField = env.GetStaticFieldID( + longClass, + 'MAX_VALUE'.toNativeChars(arena), + 'J'.toNativeChars(arena), + ); + final maxValue = env.GetStaticLongField(longClass, maxField); + expect(maxValue, equals(maxLongInJava)); + env.DeleteGlobalRef(longClass); + }); + }); + + testRunner('class <-> object methods', () { + using((arena) { + final systemOut = Jni.retrieveStaticField( + "java/lang/System", "out", "Ljava/io/PrintStream;"); + final systemErr = Jni.retrieveStaticField( + "java/lang/System", "err", "Ljava/io/PrintStream;"); + final outClass = env.GetObjectClass(systemOut); + expect(env.IsInstanceOf(systemOut, outClass), isTrue); + expect(env.IsInstanceOf(systemErr, outClass), isTrue); + final errClass = env.GetObjectClass(systemErr); + expect(env.IsSameObject(outClass, errClass), isTrue); + env.deleteAllRefs([systemOut, systemErr, outClass, errClass]); + }); + }); +} diff --git a/pkgs/jni/test/jarray_test.dart b/pkgs/jni/test/jarray_test.dart new file mode 100644 index 000000000..064bc84ef --- /dev/null +++ b/pkgs/jni/test/jarray_test.dart @@ -0,0 +1,374 @@ +// 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. + +import 'dart:io'; + +import 'package:jni/jni.dart'; +import 'package:test/test.dart'; + +import 'test_util/test_util.dart'; + +void main() { + // Don't forget to initialize JNI. + if (!Platform.isAndroid) { + checkDylibIsUpToDate(); + Jni.spawnIfNotExists(dylibDir: "build/jni_libs", jvmOptions: ["-Xmx128m"]); + } + run(testRunner: test); +} + +void run({required TestRunnerCallback testRunner}) { + testRunner("Java boolean array", () { + using((arena) { + final array = JArray(jboolean.type, 3)..releasedBy(arena); + expect(array.length, 3); + array[0] = true; + array[1] = false; + array[2] = false; + expect(array[0], true); + expect(array[1], false); + expect(array[2], false); + array.setRange(0, 3, [false, true, true, true], 1); + expect(array[0], true); + expect(array[1], true); + expect(array[2], true); + expect(() { + final _ = array[-1]; + }, throwsRangeError); + expect(() { + array[-1] = false; + }, throwsRangeError); + expect(() { + array[3] = false; + }, throwsRangeError); + }); + }); + testRunner("Java char array", () { + using((arena) { + final array = JArray(jchar.type, 3)..releasedBy(arena); + expect(array.length, 3); + array[0] = 'ح'; + array[1] = '2'; + array[2] = '3'; + expect(array[0], 'ح'); + expect(array[1], '2'); + expect(array[2], '3'); + array.setRange(0, 3, ['4', '5', '6', '7'], 1); + expect(array[0], '5'); + expect(array[1], '6'); + expect(array[2], '7'); + expect(() { + final _ = array[-1]; + }, throwsRangeError); + expect(() { + array[-1] = '4'; + }, throwsRangeError); + expect(() { + array[3] = '4'; + }, throwsRangeError); + }); + }); + testRunner("Java byte array", () { + using((arena) { + final array = JArray(jbyte.type, 3)..releasedBy(arena); + expect(array.length, 3); + array[0] = 1; + array[1] = 2; + array[2] = 3 + 256 * 5; // truncates the input; + expect(array[0], 1); + expect(array[1], 2); + expect(array[2], 3); + array.setRange(0, 3, [4, 5, 6, 7], 1); + expect(array[0], 5); + expect(array[1], 6); + expect(array[2], 7); + expect(() { + final _ = array[-1]; + }, throwsRangeError); + expect(() { + array[-1] = 4; + }, throwsRangeError); + expect(() { + array[3] = 4; + }, throwsRangeError); + }); + }); + testRunner("Java short array", () { + using((arena) { + final array = JArray(jshort.type, 3)..releasedBy(arena); + expect(array.length, 3); + array[0] = 1; + array[1] = 2; + array[2] = 3 + 256 * 256 * 5; // truncates the input + expect(array[0], 1); + expect(array[1], 2); + expect(array[2], 3); + array.setRange(0, 3, [4, 5, 6, 7], 1); + expect(array[0], 5); + expect(array[1], 6); + expect(array[2], 7); + expect(() { + final _ = array[-1]; + }, throwsRangeError); + expect(() { + array[-1] = 4; + }, throwsRangeError); + expect(() { + array[3] = 4; + }, throwsRangeError); + }); + }); + testRunner("Java int array", () { + using((arena) { + final array = JArray(jint.type, 3)..releasedBy(arena); + expect(array.length, 3); + array[0] = 1; + array[1] = 2; + array[2] = 3 + 256 * 256 * 256 * 256 * 5; // truncates the input + expect(array[0], 1); + expect(array[1], 2); + expect(array[2], 3); + array.setRange(0, 3, [4, 5, 6, 7], 1); + expect(array[0], 5); + expect(array[1], 6); + expect(array[2], 7); + expect(() { + final _ = array[-1]; + }, throwsRangeError); + expect(() { + array[-1] = 4; + }, throwsRangeError); + expect(() { + array[3] = 4; + }, throwsRangeError); + }); + }); + testRunner("Java long array", () { + using((arena) { + final array = JArray(jlong.type, 3)..releasedBy(arena); + expect(array.length, 3); + array[0] = 1; + array[1] = 2; + array[2] = 3 + 256 * 256 * 256 * 256 * 5; + expect(array[0], 1); + expect(array[1], 2); + expect(array[2], 3 + 256 * 256 * 256 * 256 * 5); + array.setRange(0, 3, [4, 5, 6, 7], 1); + expect(array[0], 5); + expect(array[1], 6); + expect(array[2], 7); + expect(() { + final _ = array[-1]; + }, throwsRangeError); + expect(() { + array[-1] = 4; + }, throwsRangeError); + expect(() { + array[3] = 4; + }, throwsRangeError); + }); + }); + const epsilon = 1e-6; + testRunner("Java float array", () { + using((arena) { + final array = JArray(jfloat.type, 3)..releasedBy(arena); + expect(array.length, 3); + array[0] = 0.5; + array[1] = 2; + array[2] = 3; + expect(array[0], closeTo(0.5, epsilon)); + expect(array[1], closeTo(2, epsilon)); + expect(array[2], closeTo(3, epsilon)); + array.setRange(0, 3, [4, 5, 6, 7], 1); + expect(array[0], closeTo(5, epsilon)); + expect(array[1], closeTo(6, epsilon)); + expect(array[2], closeTo(7, epsilon)); + expect(() { + final _ = array[-1]; + }, throwsRangeError); + expect(() { + array[-1] = 4; + }, throwsRangeError); + expect(() { + array[3] = 4; + }, throwsRangeError); + }); + }); + testRunner("Java double array", () { + using((arena) { + final array = JArray(jdouble.type, 3)..releasedBy(arena); + expect(array.length, 3); + array[0] = 0.5; + array[1] = 2; + array[2] = 3; + expect(array[0], closeTo(0.5, epsilon)); + expect(array[1], closeTo(2, epsilon)); + expect(array[2], closeTo(3, epsilon)); + array.setRange(0, 3, [4, 5, 6, 7], 1); + expect(array[0], closeTo(5, epsilon)); + expect(array[1], closeTo(6, epsilon)); + expect(array[2], closeTo(7, epsilon)); + expect(() { + final _ = array[-1]; + }, throwsRangeError); + expect(() { + array[-1] = 4; + }, throwsRangeError); + expect(() { + array[3] = 4; + }, throwsRangeError); + }); + }); + testRunner("Java string array", () { + using((arena) { + final array = JArray(JString.type, 3)..releasedBy(arena); + expect(array.length, 3); + array[0] = "حس".toJString()..releasedBy(arena); + array[1] = "\$".toJString()..releasedBy(arena); + array[2] = "33".toJString()..releasedBy(arena); + expect(array[0].toDartString(releaseOriginal: true), "حس"); + expect(array[1].toDartString(releaseOriginal: true), "\$"); + expect(array[2].toDartString(releaseOriginal: true), "33"); + array.setRange( + 0, + 3, + [ + "44".toJString()..releasedBy(arena), + "55".toJString()..releasedBy(arena), + "66".toJString()..releasedBy(arena), + "77".toJString()..releasedBy(arena), + ], + 1, + ); + expect(array[0].toDartString(releaseOriginal: true), "55"); + expect(array[1].toDartString(releaseOriginal: true), "66"); + expect(array[2].toDartString(releaseOriginal: true), "77"); + expect(() { + final _ = array[-1]; + }, throwsRangeError); + expect(() { + array[-1] = "44".toJString()..releasedBy(arena); + }, throwsRangeError); + expect(() { + array[3] = "44".toJString()..releasedBy(arena); + }, throwsRangeError); + }); + }); + testRunner("Java object array", () { + using((arena) { + final array = JArray(JObject.type, 3)..releasedBy(arena); + expect(array.length, 3); + expect(array[0].reference, nullptr); + expect(array[1].reference, nullptr); + expect(array[2].reference, nullptr); + }); + }); + testRunner("Java 2d array", () { + using((arena) { + final array = JArray(jint.type, 3)..releasedBy(arena); + array[0] = 1; + array[1] = 2; + array[2] = 3; + final twoDimArray = JArray(JArray.type(jint.type), 3)..releasedBy(arena); + expect(twoDimArray.length, 3); + twoDimArray[0] = array; + twoDimArray[1] = array; + twoDimArray[2] = array; + for (var i = 0; i < 3; ++i) { + expect(twoDimArray[i][0], 1); + expect(twoDimArray[i][1], 2); + expect(twoDimArray[i][2], 3); + } + twoDimArray[2][2] = 4; + expect(twoDimArray[2][2], 4); + }); + }); + testRunner("JArray.filled", () { + using((arena) { + final string = "abc".toJString()..releasedBy(arena); + final array = JArray.filled(3, string)..releasedBy(arena); + expect( + () => JArray.filled(-3, JString.fromRef(nullptr)), + throwsA(isA()), + ); + expect(array.length, 3); + expect(array[0].toDartString(releaseOriginal: true), "abc"); + expect(array[1].toDartString(releaseOriginal: true), "abc"); + expect(array[2].toDartString(releaseOriginal: true), "abc"); + }); + }); + testRunner('JArray of JByte', () { + using((arena) { + final arr = JArray(JByte.type, 1)..releasedBy(arena); + expect((arr[0]..releasedBy(arena)).isNull, true); + }); + }); + testRunner('JArray of JShort', () { + using((arena) { + final arr = JArray(JShort.type, 1)..releasedBy(arena); + expect((arr[0]..releasedBy(arena)).isNull, true); + }); + }); + testRunner('JArray of JInteger', () { + using((arena) { + final arr = JArray(JInteger.type, 1)..releasedBy(arena); + expect((arr[0]..releasedBy(arena)).isNull, true); + }); + }); + testRunner('JArray of JCharacter', () { + using((arena) { + final arr = JArray(JCharacter.type, 1)..releasedBy(arena); + expect((arr[0]..releasedBy(arena)).isNull, true); + }); + }); + testRunner('JArray of JLong', () { + using((arena) { + final arr = JArray(JLong.type, 1)..releasedBy(arena); + expect((arr[0]..releasedBy(arena)).isNull, true); + }); + }); + testRunner('JArray of JFloat', () { + using((arena) { + final arr = JArray(JFloat.type, 1)..releasedBy(arena); + expect((arr[0]..releasedBy(arena)).isNull, true); + }); + }); + testRunner('JArray of JDouble', () { + using((arena) { + final arr = JArray(JDouble.type, 1)..releasedBy(arena); + expect((arr[0]..releasedBy(arena)).isNull, true); + }); + }); + testRunner('JArray of JBoolean', () { + using((arena) { + final arr = JArray(JBoolean.type, 1)..releasedBy(arena); + expect((arr[0]..releasedBy(arena)).isNull, true); + }); + }); + testRunner('JArray of JSet', () { + using((arena) { + final arr = JArray(JSet.type(JString.type), 1)..releasedBy(arena); + expect((arr[0]..releasedBy(arena)).isNull, true); + }); + }); + testRunner('JArray of JList', () { + using((arena) { + final arr = JArray(JList.type(JString.type), 1)..releasedBy(arena); + expect((arr[0]..releasedBy(arena)).isNull, true); + }); + }); + testRunner('JArray of JMap', () { + using((arena) { + final arr = JArray(JMap.type(JString.type, JString.type), 1) + ..releasedBy(arena); + expect((arr[0]..releasedBy(arena)).isNull, true); + }); + }); + testRunner('JArray of JIterator', () { + using((arena) { + final arr = JArray(JIterator.type(JString.type), 1)..releasedBy(arena); + expect((arr[0]..releasedBy(arena)).isNull, true); + }); + }); +} diff --git a/pkgs/jni/test/jbyte_buffer_test.dart b/pkgs/jni/test/jbyte_buffer_test.dart new file mode 100644 index 000000000..48f9eaf45 --- /dev/null +++ b/pkgs/jni/test/jbyte_buffer_test.dart @@ -0,0 +1,229 @@ +// Copyright (c) 2023, 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. + +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:jni/jni.dart'; +import 'package:test/test.dart'; + +import 'test_util/test_util.dart'; + +void main() { + // Don't forget to initialize JNI. + if (!Platform.isAndroid) { + checkDylibIsUpToDate(); + Jni.spawnIfNotExists(dylibDir: "build/jni_libs", jvmOptions: ["-Xmx128m"]); + } + run(testRunner: test); +} + +void run({required TestRunnerCallback testRunner}) { + final throwsAJniException = throwsA(isA()); + JByteBuffer testDataBuffer(Arena arena) { + final buffer = JByteBuffer.allocate(3)..releasedBy(arena); + buffer.nextByte = 1; + buffer.nextByte = 2; + buffer.nextByte = 3; + buffer.position = 0; + return buffer; + } + + testRunner('wrap whole array', () { + using((arena) { + final array = JArray(jbyte.type, 3)..releasedBy(arena); + array[0] = 1; + array[1] = 2; + array[2] = 3; + final buffer = JByteBuffer.wrap(array)..releasedBy(arena); + expect(buffer, testDataBuffer(arena)); + }); + }); + + testRunner('wrap partial array', () { + using((arena) { + final array = JArray(jbyte.type, 3)..releasedBy(arena); + array[0] = 1; + array[1] = 2; + array[2] = 3; + final buffer = JByteBuffer.wrap(array, 1, 1)..releasedBy(arena); + expect(buffer.nextByte, 2); + expect(() => buffer.nextByte, throwsAJniException); + }); + }); + + testRunner('capacity', () { + using((arena) { + final buffer = testDataBuffer(arena); + expect(buffer.capacity, 3); + }); + }); + + testRunner('position', () { + using((arena) { + final buffer = testDataBuffer(arena); + expect(buffer.position, 0); + buffer.position = 2; + expect(buffer.position, 2); + }); + }); + + testRunner('limit', () { + using((arena) { + final buffer = testDataBuffer(arena); + expect(buffer.limit, 3); + buffer.limit = 2; + expect(buffer.limit, 2); + }); + }); + + testRunner('mark and reset', () { + using((arena) { + final buffer = testDataBuffer(arena); + buffer.position = 1; + buffer.mark(); + buffer.position = 2; + buffer.reset(); + expect(buffer.position, 1); + }); + }); + + testRunner('clear', () { + using((arena) { + final buffer = testDataBuffer(arena); + buffer.position = 2; + buffer.limit = 2; + buffer.clear(); + expect(buffer.limit, 3); + expect(buffer.position, 0); + }); + }); + + testRunner('flip', () { + using((arena) { + final buffer = testDataBuffer(arena); + buffer.position = 2; + buffer.flip(); + expect(buffer.limit, 2); + expect(buffer.position, 0); + }); + }); + + testRunner('rewind', () { + using((arena) { + final buffer = testDataBuffer(arena); + buffer.mark(); + buffer.position = 2; + buffer.rewind(); + expect(buffer.position, 0); + expect(buffer.reset, throwsAJniException); + }); + }); + + testRunner('remaining and hasRemaining', () { + using((arena) { + final buffer = testDataBuffer(arena); + buffer.position = 2; + expect(buffer.remaining, 1); + expect(buffer.hasRemaining, true); + buffer.position = 3; + expect(buffer.remaining, 0); + expect(buffer.hasRemaining, false); + }); + }); + + testRunner('isReadOnly and asReadOnlyBuffer', () { + using((arena) { + final buffer = testDataBuffer(arena); + expect(buffer.isReadOnly, false); + final readOnly = buffer.asReadOnlyBuffer()..releasedBy(arena); + expect(readOnly.isReadOnly, true); + }); + }); + + testRunner('hasArray, array and arrayOffset', () { + using((arena) { + final buffer = testDataBuffer(arena); + expect(buffer.hasArray, true); + expect(buffer.arrayOffset, 0); + expect(buffer.array.length, 3); + final directBuffer = JByteBuffer.allocateDirect(3)..releasedBy(arena); + expect(directBuffer.hasArray, false); + }); + }); + + testRunner('isDirect', () { + using((arena) { + final buffer = testDataBuffer(arena); + expect(buffer.isDirect, false); + final directBuffer = JByteBuffer.allocateDirect(3)..releasedBy(arena); + expect(directBuffer.isDirect, true); + }); + }); + + testRunner('slice', () { + using((arena) { + final buffer = testDataBuffer(arena); + buffer.position = 1; + buffer.limit = 2; + final sliced = buffer.slice()..releasedBy(arena); + expect(sliced.capacity, 1); + expect(sliced.nextByte, 2); + }); + }); + + testRunner('duplicate', () { + using((arena) { + final buffer = testDataBuffer(arena); + buffer.position = 1; + buffer.limit = 2; + final duplicate = buffer.duplicate()..releasedBy(arena); + expect(duplicate.capacity, 3); + expect(duplicate.position, 1); + expect(duplicate.limit, 2); + }); + }); + + testRunner('asUint8List', () { + using((arena) { + final buffer = testDataBuffer(arena); + expect(buffer.asUint8List, throwsA(isA())); + final list = Uint8List.fromList([1, 2, 3]); + final directBuffer = list.toJByteBuffer()..releasedBy(arena); + expect(directBuffer.asUint8List(), list); + }); + }); + + testRunner('type hashCode, ==', () { + using((arena) { + final a = testDataBuffer(arena); + final b = testDataBuffer(arena); + expect(a.$type, b.$type); + expect(a.$type.hashCode, b.$type.hashCode); + final c = JBuffer.fromRef(nullptr); + final d = JBuffer.fromRef(nullptr); + expect(c.$type, d.$type); + expect(c.$type.hashCode, d.$type.hashCode); + + expect(a.$type, isNot(c.$type)); + expect(a.$type.hashCode, isNot(c.$type.hashCode)); + }); + }); + + testRunner('asUint8List releasing original', () { + using((arena) { + // Used as an example in [JByteBuffer]. + final directBuffer = JByteBuffer.allocateDirect(3); + final data1 = directBuffer.asUint8List(); + directBuffer.nextByte = 42; // No problem! + expect(data1[0], 42); + final data2 = directBuffer.asUint8List(releaseOriginal: true); + expect( + () => directBuffer.nextByte = 42, + throwsA(isA()), + ); + expect(data2[0], 42); + }); + }); +} diff --git a/pkgs/jni/test/jfinal_string_test.dart b/pkgs/jni/test/jfinal_string_test.dart new file mode 100644 index 000000000..c8a998001 --- /dev/null +++ b/pkgs/jni/test/jfinal_string_test.dart @@ -0,0 +1,43 @@ +// Copyright (c) 2023, 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. + +import 'dart:io'; + +import 'package:jni/jni.dart'; +import 'package:jni/src/jfinal_string.dart'; +import 'package:test/test.dart'; + +import 'test_util/test_util.dart'; + +void main() { + // Don't forget to initialize JNI. + if (!Platform.isAndroid) { + checkDylibIsUpToDate(); + Jni.spawnIfNotExists(dylibDir: "build/jni_libs", jvmOptions: ["-Xmx128m"]); + } + run(testRunner: test); +} + +void run({required TestRunnerCallback testRunner}) { + testRunner('JFinalString', () { + const string = 'abc'; + var referenceFetchedCount = 0; + final finalString = JFinalString( + () { + ++referenceFetchedCount; + return string.toJString().reference; + }, + string, + ); + expect(finalString.toDartString(), string); + expect(referenceFetchedCount, 0); + expect(finalString.reference, isNot(nullptr)); + expect(referenceFetchedCount, 1); + finalString.reference; + expect(referenceFetchedCount, 1); + expect(finalString.toDartString(releaseOriginal: true), string); + expect(() => finalString.reference, throwsA(isA())); + expect(finalString.release, throwsA(isA())); + }); +} diff --git a/pkgs/jni/test/jlist_test.dart b/pkgs/jni/test/jlist_test.dart new file mode 100644 index 000000000..b410525be --- /dev/null +++ b/pkgs/jni/test/jlist_test.dart @@ -0,0 +1,216 @@ +// Copyright (c) 2023, 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. + +import 'dart:io'; + +import 'package:jni/jni.dart'; +import 'package:test/test.dart'; + +import 'test_util/test_util.dart'; + +void main() { + // Don't forget to initialize JNI. + if (!Platform.isAndroid) { + checkDylibIsUpToDate(); + Jni.spawnIfNotExists(dylibDir: "build/jni_libs", jvmOptions: ["-Xmx128m"]); + } + run(testRunner: test); +} + +void run({required TestRunnerCallback testRunner}) { + JList testDataList(Arena arena) { + return [ + "1".toJString()..releasedBy(arena), + "2".toJString()..releasedBy(arena), + "3".toJString()..releasedBy(arena), + ].toJList(JString.type) + ..releasedBy(arena); + } + + testRunner('length get', () { + using((arena) { + final list = testDataList(arena); + expect(list.length, 3); + }); + }); + testRunner('length set', () { + using((arena) { + final list = testDataList(arena); + list.length = 2; + expect(list.length, 2); + list.length = 3; + expect(list.length, 3); + expect(list.last.isNull, true); + }); + }); + testRunner('[]', () { + using((arena) { + final list = testDataList(arena); + expect(list[0].toDartString(releaseOriginal: true), "1"); + expect(list[1].toDartString(releaseOriginal: true), "2"); + expect(list[2].toDartString(releaseOriginal: true), "3"); + }); + }); + testRunner('[]=', () { + using((arena) { + final list = testDataList(arena); + expect(list[0].toDartString(releaseOriginal: true), "1"); + list[0] = "2".toJString()..releasedBy(arena); + expect(list[0].toDartString(releaseOriginal: true), "2"); + }); + }); + testRunner('add', () { + using((arena) { + final list = testDataList(arena); + list.add("4".toJString()..releasedBy(arena)); + expect(list.length, 4); + expect(list[3].toDartString(releaseOriginal: true), "4"); + }); + }); + testRunner('addAll', () { + using((arena) { + final list = testDataList(arena); + final toAppend = testDataList(arena); + list.addAll(toAppend); + expect(list.length, 6); + list.addAll(["4".toJString()..releasedBy(arena)]); + expect(list.length, 7); + }); + }); + testRunner('clear, isEmpty, isNotEmpty', () { + using((arena) { + final list = testDataList(arena); + expect(list.isNotEmpty, true); + expect(list.isEmpty, false); + list.clear(); + expect(list.isNotEmpty, false); + expect(list.isEmpty, true); + }); + }); + testRunner('contains', () { + using((arena) { + final list = testDataList(arena); + // ignore: iterable_contains_unrelated_type + expect(list.contains("1"), false); + expect(list.contains("1".toJString()..releasedBy(arena)), true); + expect(list.contains("4".toJString()..releasedBy(arena)), false); + }); + }); + testRunner('getRange', () { + using((arena) { + final list = testDataList(arena); + // ignore: iterable_contains_unrelated_type + final range = list.getRange(1, 2)..releasedBy(arena); + expect(range.length, 1); + expect(range.first.toDartString(releaseOriginal: true), "2"); + }); + }); + testRunner('indexOf', () { + using((arena) { + final list = testDataList(arena); + expect(list.indexOf(1), -1); + expect(list.indexOf("1".toJString()..toDartString()), 0); + expect(list.indexOf("2".toJString()..toDartString()), 1); + expect(list.indexOf("1".toJString()..toDartString(), 1), -1); + expect(list.indexOf("1".toJString()..toDartString(), -1), 0); + }); + }); + testRunner('insert', () { + using((arena) { + final list = testDataList(arena); + list.insert(1, "0".toJString()..releasedBy(arena)); + expect(list.length, 4); + expect(list[1].toDartString(releaseOriginal: true), "0"); + }); + }); + testRunner('insertAll', () { + using((arena) { + final list = testDataList(arena); + final toInsert = testDataList(arena); + list.insertAll(1, toInsert); + expect(list[1].toDartString(releaseOriginal: true), "1"); + expect(list.length, 6); + list.insertAll(1, ["4".toJString()..releasedBy(arena)]); + expect(list.length, 7); + expect(list[1].toDartString(releaseOriginal: true), "4"); + }); + }); + testRunner('iterator', () { + using((arena) { + final list = testDataList(arena); + final it = list.iterator; + expect(it.moveNext(), true); + expect(it.current.toDartString(releaseOriginal: true), "1"); + expect(it.moveNext(), true); + expect(it.current.toDartString(releaseOriginal: true), "2"); + expect(it.moveNext(), true); + expect(it.current.toDartString(releaseOriginal: true), "3"); + expect(it.moveNext(), false); + }); + }); + testRunner('remove', () { + using((arena) { + final list = testDataList(arena); + expect(list.remove("3".toJString()..releasedBy(arena)), true); + expect(list.length, 2); + expect(list.remove("4".toJString()..releasedBy(arena)), false); + // ignore: list_remove_unrelated_type + expect(list.remove(1), false); + }); + }); + testRunner('removeAt', () { + using((arena) { + final list = testDataList(arena); + expect(list.removeAt(0).toDartString(releaseOriginal: true), "1"); + expect(list.removeAt(1).toDartString(releaseOriginal: true), "3"); + }); + }); + testRunner('removeRange', () { + using((arena) { + final list = testDataList(arena); + list.removeRange(0, 2); + expect(list.single.toDartString(releaseOriginal: true), "3"); + }); + }); + testRunner('==, hashCode', () { + using((arena) { + final a = testDataList(arena); + final b = testDataList(arena); + expect(a.hashCode, b.hashCode); + expect(a, b); + b.add("4".toJString()..releasedBy(arena)); + expect(a.hashCode, isNot(b.hashCode)); + expect(a, isNot(b)); + }); + }); + testRunner('toSet', () { + using((arena) { + final list = testDataList(arena); + final set = list.toSet()..releasedBy(arena); + expect(set.length, 3); + }); + }); + testRunner('type hashCode, ==', () { + using((arena) { + final a = testDataList(arena); + final b = testDataList(arena); + expect(a.$type, b.$type); + expect(a.$type.hashCode, b.$type.hashCode); + final c = JList.array(JObject.type)..releasedBy(arena); + expect(a.$type, isNot(c.$type)); + expect(a.$type.hashCode, isNot(c.$type.hashCode)); + }); + }); + testRunner('JIterator type hashCode, ==', () { + using((arena) { + final a = testDataList(arena); + final b = testDataList(arena); + expect(a.iterator.$type, b.iterator.$type); + expect(a.iterator.$type.hashCode, b.iterator.$type.hashCode); + final c = JList.array(JObject.type)..releasedBy(arena); + expect(a.iterator.$type, isNot(c.iterator.$type)); + expect(a.iterator.$type.hashCode, isNot(c.iterator.$type.hashCode)); + }); + }); +} diff --git a/pkgs/jni/test/jmap_test.dart b/pkgs/jni/test/jmap_test.dart new file mode 100644 index 000000000..4ece7517f --- /dev/null +++ b/pkgs/jni/test/jmap_test.dart @@ -0,0 +1,170 @@ +// Copyright (c) 2023, 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. + +import 'dart:io'; + +import 'package:jni/jni.dart'; +import 'package:test/test.dart'; + +import 'test_util/test_util.dart'; + +void main() { + // Don't forget to initialize JNI. + if (!Platform.isAndroid) { + Jni.spawnIfNotExists(dylibDir: "build/jni_libs", jvmOptions: ["-Xmx128m"]); + } + run(testRunner: test); +} + +void run({required TestRunnerCallback testRunner}) { + JMap testDataMap(Arena arena) { + return { + "1".toJString()..releasedBy(arena): "One".toJString()..releasedBy(arena), + "2".toJString()..releasedBy(arena): "Two".toJString()..releasedBy(arena), + "3".toJString()..releasedBy(arena): "Three".toJString() + ..releasedBy(arena), + }.toJMap(JString.type, JString.type) + ..releasedBy(arena); + } + + testRunner('length', () { + using((arena) { + final map = testDataMap(arena); + expect(map.length, 3); + }); + }); + testRunner('[]', () { + using((arena) { + final map = testDataMap(arena); + // ignore: collection_methods_unrelated_type + expect(map[1], null); + expect( + map["1".toJString()..releasedBy(arena)] + ?.toDartString(releaseOriginal: true), + "One", + ); + expect( + map["4".toJString()..releasedBy(arena)], + null, + ); + }); + }); + testRunner('[]=', () { + using((arena) { + final map = testDataMap(arena); + map["0".toJString()..releasedBy(arena)] = "Zero".toJString() + ..releasedBy(arena); + expect( + map["0".toJString()..releasedBy(arena)] + ?.toDartString(releaseOriginal: true), + "Zero", + ); + expect(map.length, 4); + map["1".toJString()..releasedBy(arena)] = "one!".toJString() + ..releasedBy(arena); + expect( + map["1".toJString()..releasedBy(arena)] + ?.toDartString(releaseOriginal: true), + "one!", + ); + expect(map.length, 4); + }); + }); + testRunner('addAll', () { + using((arena) { + final map = testDataMap(arena); + final toAdd = { + "0".toJString()..releasedBy(arena): "Zero".toJString() + ..releasedBy(arena), + "1".toJString()..releasedBy(arena): "one!".toJString() + ..releasedBy(arena), + }.toJMap(JString.type, JString.type); + map.addAll(toAdd); + expect(map.length, 4); + expect( + map["0".toJString()..releasedBy(arena)] + ?.toDartString(releaseOriginal: true), + "Zero", + ); + expect( + map["1".toJString()..releasedBy(arena)] + ?.toDartString(releaseOriginal: true), + "one!", + ); + map.addAll({ + "4".toJString()..releasedBy(arena): "Four".toJString() + ..releasedBy(arena) + }); + expect(map.length, 5); + }); + }); + testRunner('clear, isEmpty, isNotEmpty', () { + using((arena) { + final map = testDataMap(arena); + expect(map.isEmpty, false); + expect(map.isNotEmpty, true); + map.clear(); + expect(map.isEmpty, true); + expect(map.isNotEmpty, false); + }); + }); + testRunner('containsKey', () { + using((arena) { + final map = testDataMap(arena); + // ignore: iterable_contains_unrelated_type + expect(map.containsKey(1), false); + expect(map.containsKey("1".toJString()..releasedBy(arena)), true); + expect(map.containsKey("4".toJString()..releasedBy(arena)), false); + }); + }); + testRunner('containsValue', () { + using((arena) { + final map = testDataMap(arena); + // ignore: iterable_contains_unrelated_type + expect(map.containsValue(1), false); + expect(map.containsValue("One".toJString()..releasedBy(arena)), true); + expect(map.containsValue("Four".toJString()..releasedBy(arena)), false); + }); + }); + testRunner('keys', () { + using((arena) { + final map = testDataMap(arena); + final keys = map.keys; + expect( + keys + .map((element) => element.toDartString(releaseOriginal: true)) + .toSet(), + {"1", "2", "3"}, + ); + }); + }); + testRunner('remove', () { + using((arena) { + final map = testDataMap(arena); + // ignore: collection_methods_unrelated_type + expect(map.remove(1), null); + expect(map.remove("4".toJString()..releasedBy(arena)), null); + expect(map.length, 3); + expect( + map + .remove("3".toJString()..releasedBy(arena)) + ?.toDartString(releaseOriginal: true), + "Three", + ); + expect(map.length, 2); + }); + }); + testRunner('type hashCode, ==', () { + using((arena) { + final a = testDataMap(arena); + final b = testDataMap(arena); + expect(a.$type, b.$type); + expect(a.$type, b.$type); + expect(a.$type.hashCode, b.$type.hashCode); + final c = JMap.hash(JObject.type, JObject.type)..releasedBy(arena); + expect(a.$type, isNot(c.$type)); + expect(a.$type.hashCode, isNot(c.$type.hashCode)); + }); + }); +} diff --git a/pkgs/jni/test/jobject_test.dart b/pkgs/jni/test/jobject_test.dart new file mode 100644 index 000000000..a63828cfb --- /dev/null +++ b/pkgs/jni/test/jobject_test.dart @@ -0,0 +1,293 @@ +// 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. + +import 'dart:io'; +import 'dart:ffi'; +import 'dart:isolate'; + +import 'package:test/test.dart'; + +import 'package:jni/jni.dart'; + +import 'test_util/test_util.dart'; + +const maxLongInJava = 9223372036854775807; + +void main() { + // Don't forget to initialize JNI. + if (!Platform.isAndroid) { + checkDylibIsUpToDate(); + Jni.spawnIfNotExists(dylibDir: "build/jni_libs", jvmOptions: ["-Xmx128m"]); + } + run(testRunner: test); +} + +void run({required TestRunnerCallback testRunner}) { + // The API based on JniEnv is intended to closely mimic C API of JNI, + // And thus can be too verbose for simple experimenting and one-off uses + // JObject API provides an easier way to perform some common operations. + // + // However, if binding generation using jnigen is possible, that should be + // the first choice. + testRunner("Long.intValue() using JObject", () { + // JClass wraps a local class reference, and + // provides convenience functions. + final longClass = Jni.findJClass("java/lang/Long"); + + // looks for a constructor with given signature. + // equivalently you can lookup a method with name + final longCtor = longClass.getCtorID("(J)V"); + + // note that the arguments are just passed as a list. + // allowed argument types are primitive types, JObject and its subclasses, + // and raw JNI references (JObject). Strings will be automatically converted + // to JNI strings. + final long = longClass.newInstance(longCtor, [176]); + + final intValue = long.callMethodByName( + "intValue", + "()I", + [], + JniCallType.intType, + ); + expect(intValue, equals(176)); + + // Release any JObject and JClass instances using `.release()` after use. + // This is not strictly required since JNI objects / classes have + // a [NativeFinalizer]. But deleting them after use is a good practice. + long.release(); + longClass.release(); + }); + + testRunner("call a static method using JClass APIs", () { + final integerClass = Jni.findJClass("java/lang/Integer"); + final result = integerClass.callStaticMethodByName( + "toHexString", "(I)Ljava/lang/String;", [JValueInt(31)]); + + // If the object is supposed to be a Java string you can call + // [toDartString] on it. + final resultString = result.toDartString(); + + // Dart string is a copy, original object can be released. + result.release(); + expect(resultString, equals("1f")); + + // Also don't forget to release the class. + integerClass.release(); + }); + + testRunner("Call method with null argument, expect exception", () { + final integerClass = Jni.findJClass("java/lang/Integer"); + expect( + () => integerClass.callStaticMethodByName( + "parseInt", "(Ljava/lang/String;)I", [nullptr]), + throwsException); + integerClass.release(); + }); + + // Skip this test on Android integration test because it fails there, possibly + // due to a CheckJNI precondition check. + if (!Platform.isAndroid) { + testRunner("Try to find a non-exisiting class, expect exception", () { + expect(() => Jni.findJClass("java/lang/NotExists"), throwsException); + }); + } + + // [callMethodByName] will be expensive if making same call many times. + // Use [getMethodID] to get a method ID and use it in subsequent calls. + testRunner("Example for using getMethodID", () { + final longClass = Jni.findJClass("java/lang/Long"); + final bitCountMethod = longClass.getStaticMethodID("bitCount", "(J)I"); + + // Use newInstance if you want only one instance. + // It finds the class, gets constructor ID and constructs an instance. + final random = Jni.newInstance("java/util/Random", "()V", []); + + // You don't need a [JClass] reference to get instance method IDs. + final nextIntMethod = random.getMethodID("nextInt", "(I)I"); + + for (int i = 0; i < 100; i++) { + int r = random.callMethod( + nextIntMethod, + [JValueInt(256 * 256)], + JniCallType.intType, + ); + int bits = 0; + final jbc = longClass.callStaticMethod( + bitCountMethod, + [r], + JniCallType.intType, + ); + while (r != 0) { + bits += r % 2; + r = (r / 2).floor(); + } + expect(jbc, equals(bits)); + } + random.release(); + longClass.release(); + }); + + // One-off invocation of static method in single call. + testRunner("invoke_", () { + final m = Jni.invokeStaticMethod( + "java/lang/Short", + "compare", + "(SS)I", + [JValueShort(1234), JValueShort(1324)], + JniCallType.intType, + ); + expect(m, equals(1234 - 1324)); + }); + + testRunner("Java char from string", () { + final m = Jni.invokeStaticMethod("java/lang/Character", "isLowerCase", + "(C)Z", [JValueChar.fromString('X')]); + expect(m, isFalse); + }); + + // One-off access of static field in single call. + testRunner("Get static field directly", () { + final maxLong = Jni.retrieveStaticField( + "java/lang/Short", "MAX_VALUE", "S", JniCallType.shortType); + expect(maxLong, equals(32767)); + }); + + // Use [callStringMethod] if all you care about is a string result + testRunner("callStaticStringMethod", () { + final longClass = Jni.findJClass("java/lang/Long"); + const n = 1223334444; + final strFromJava = longClass.callStaticMethodByName( + "toOctalString", "(J)Ljava/lang/String;", [n]); + expect(strFromJava, equals(n.toRadixString(8))); + longClass.release(); + }); + + // In [JObject], [JClass], and retrieve_/invoke_ methods + // you can also pass Dart strings, apart from range of types + // allowed by [Jni.jvalues]. + // They will be converted automatically. + testRunner( + "Passing strings in arguments", + () { + final out = Jni.retrieveStaticField( + "java/lang/System", "out", "Ljava/io/PrintStream;"); + // uncomment next line to see output + // (\n because test runner prints first char at end of the line) + //out.callMethodByName( + // "println", "(Ljava/lang/Object;)V", ["\nWorks (Apparently)"]); + out.release(); + }, + ); + + testRunner("Passing strings in arguments 2", () { + final twelve = Jni.invokeStaticMethod("java/lang/Byte", "parseByte", + "(Ljava/lang/String;)B", ["12"], JniCallType.byteType); + expect(twelve, equals(12)); + }); + + // You can use() method on JObject for using once and deleting. + testRunner("use() method", () { + final randomInt = Jni.newInstance("java/util/Random", "()V", []).use( + (random) => random.callMethodByName( + "nextInt", + "(I)I", + [JValueInt(15)], + JniCallType.intType, + ), + ); + expect(randomInt, lessThan(15)); + }); + + // The JObject and JClass have NativeFinalizer. However, it's possible to + // explicitly use `Arena`. + testRunner('Using arena', () { + final objects = []; + using((arena) { + final r = Jni.findJClass('java/util/Random')..releasedBy(arena); + final ctor = r.getCtorID("()V"); + for (int i = 0; i < 10; i++) { + objects.add(r.newInstance(ctor, [])..releasedBy(arena)); + } + }); + for (var object in objects) { + expect(object.isReleased, isTrue); + } + }); + + testRunner("enums", () { + // Don't forget to escape $ in nested type names + final ordinal = Jni.retrieveStaticField( + "java/net/Proxy\$Type", "HTTP", "Ljava/net/Proxy\$Type;") + .use( + (f) => f.callMethodByName( + "ordinal", + "()I", + [], + JniCallType.intType, + ), + ); + expect(ordinal, equals(1)); + }); + + testRunner("casting", () { + using((arena) { + final str = "hello".toJString()..releasedBy(arena); + final obj = str.castTo(JObject.type)..releasedBy(arena); + final backToStr = obj.castTo(JString.type); + expect(backToStr.toDartString(), str.toDartString()); + final _ = backToStr.castTo(JObject.type, releaseOriginal: true) + ..releasedBy(arena); + expect(backToStr.toDartString, throwsA(isA())); + expect(backToStr.release, throwsA(isA())); + }); + }); + + testRunner("Isolate", () { + Isolate.spawn(doSomeWorkInIsolate, null); + }); + + testRunner("Methods rethrow exceptions in Java as JniException", () { + expect( + () => Jni.invokeStaticMethod( + "java/lang/Integer", "parseInt", "(Ljava/lang/String;)I", ["X"]), + throwsA(isA()), + ); + }); + + testRunner("Passing long integer values to JNI", () { + final maxLongStr = Jni.invokeStaticMethod( + "java/lang/Long", + "toString", + "(J)Ljava/lang/String;", + [maxLongInJava], + ); + expect(maxLongStr, equals('$maxLongInJava')); + }); + + testRunner('Returning long integers from JNI', () { + final maxLong = Jni.retrieveStaticField( + "java/lang/Long", + "MAX_VALUE", + "J", + JniCallType.longType, + ); + expect(maxLong, equals(maxLongInJava)); + }); +} + +void doSomeWorkInIsolate(Void? _) { + // On standalone target, make sure to call [setDylibDir] before accessing + // any JNI function in a new isolate. + // + // otherwise subsequent JNI calls will throw a "library not found" exception. + Jni.setDylibDir(dylibDir: "build/jni_libs"); + final random = Jni.newInstance("java/util/Random", "()V", []); + // final r = random.callMethodByName("nextInt", "(I)I", [256]); + // expect(r, lessThan(256)); + // Expect throws an [OutsideTestException] + // but you can uncomment below print and see it works + // print("\n$r"); + random.release(); +} diff --git a/pkgs/jni/test/jset_test.dart b/pkgs/jni/test/jset_test.dart new file mode 100644 index 000000000..2d93e6334 --- /dev/null +++ b/pkgs/jni/test/jset_test.dart @@ -0,0 +1,202 @@ +// Copyright (c) 2023, 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. + +import 'dart:io'; + +import 'package:jni/jni.dart'; +import 'package:test/test.dart'; + +import 'test_util/test_util.dart'; + +void main() { + // Don't forget to initialize JNI. + if (!Platform.isAndroid) { + checkDylibIsUpToDate(); + Jni.spawnIfNotExists(dylibDir: "build/jni_libs", jvmOptions: ["-Xmx128m"]); + } + run(testRunner: test); +} + +void run({required TestRunnerCallback testRunner}) { + JSet testDataSet(Arena arena) { + return { + "1".toJString()..releasedBy(arena), + "2".toJString()..releasedBy(arena), + "3".toJString()..releasedBy(arena), + }.toJSet(JString.type) + ..releasedBy(arena); + } + + testRunner('length', () { + using((arena) { + final set = testDataSet(arena); + expect(set.length, 3); + }); + }); + testRunner('add', () { + using((arena) { + final set = testDataSet(arena); + set.add("1".toJString()..releasedBy(arena)); + expect(set.length, 3); + set.add("4".toJString()..releasedBy(arena)); + expect(set.length, 4); + }); + }); + testRunner('addAll', () { + using((arena) { + final set = testDataSet(arena); + final toAdd = testDataSet(arena); + toAdd.add("4".toJString()..releasedBy(arena)); + set.addAll(toAdd); + expect(set.length, 4); + set.addAll([ + "1".toJString()..releasedBy(arena), + "5".toJString()..releasedBy(arena), + ]); + expect(set.length, 5); + }); + }); + testRunner('clear, isEmpty, isNotEmpty', () { + using((arena) { + final set = testDataSet(arena); + set.clear(); + expect(set.isEmpty, true); + expect(set.isNotEmpty, false); + }); + }); + testRunner('contains', () { + using((arena) { + final set = testDataSet(arena); + // ignore: iterable_contains_unrelated_type + expect(set.contains(1), false); + expect(set.contains("1".toJString()..releasedBy(arena)), true); + expect(set.contains("4".toJString()..releasedBy(arena)), false); + }); + }); + testRunner('containsAll', () { + using((arena) { + final set = testDataSet(arena); + expect(set.containsAll(set), true); + expect( + set.containsAll([ + "1".toJString()..releasedBy(arena), + "2".toJString()..releasedBy(arena), + ]), + true, + ); + final testSet = testDataSet(arena); + testSet.add("4".toJString()..releasedBy(arena)); + expect(set.containsAll(testSet), false); + expect(set.containsAll(["4".toJString()..releasedBy(arena)]), false); + }); + }); + testRunner('iterator', () { + using((arena) { + final set = testDataSet(arena); + final it = set.iterator; + // There are no order guarantees in a hashset. + final dartSet = {}; + expect(it.moveNext(), true); + dartSet.add(it.current.toDartString(releaseOriginal: true)); + expect(it.moveNext(), true); + dartSet.add(it.current.toDartString(releaseOriginal: true)); + expect(it.moveNext(), true); + dartSet.add(it.current.toDartString(releaseOriginal: true)); + expect(it.moveNext(), false); + // So we just check if the elements have appeared in some order. + expect(dartSet, {"1", "2", "3"}); + }); + }); + testRunner('remove', () { + using((arena) { + final set = testDataSet(arena); + // ignore: collection_methods_unrelated_type + expect(set.remove(1), false); + expect(set.remove("4".toJString()..releasedBy(arena)), false); + expect(set.length, 3); + expect(set.remove("3".toJString()..releasedBy(arena)), true); + expect(set.length, 2); + }); + }); + testRunner('removeAll', () { + using((arena) { + final set = testDataSet(arena); + final toRemoveExclusive = {"4".toJString()..releasedBy(arena)} + .toJSet(JString.type) + ..releasedBy(arena); + set.removeAll(toRemoveExclusive); + expect(set.length, 3); + final toRemoveInclusive = { + "1".toJString()..releasedBy(arena), + "4".toJString()..releasedBy(arena), + }.toJSet(JString.type) + ..releasedBy(arena); + set.removeAll(toRemoveInclusive); + expect(set.length, 2); + set.removeAll(["2".toJString()..releasedBy(arena)]); + expect(set.length, 1); + }); + }); + testRunner('retainAll', () { + using((arena) { + final set = testDataSet(arena); + final toRetain = { + "1".toJString()..releasedBy(arena), + "3".toJString()..releasedBy(arena), + "4".toJString()..releasedBy(arena), + }; + set.retainAll(set); + expect(set.length, 3); + set.retainAll(toRetain); + expect(set.length, 2); + final toRetainJSet = toRetain.toJSet(JString.type)..releasedBy(arena); + set.retainAll(toRetainJSet); + expect(set.length, 2); + }); + }); + testRunner('==, hashCode', () { + using((arena) { + final a = testDataSet(arena); + final b = testDataSet(arena); + expect(a.hashCode, b.hashCode); + expect(a, b); + b.add("4".toJString()..releasedBy(arena)); + expect(a.hashCode, isNot(b.hashCode)); + expect(a, isNot(b)); + }); + }); + testRunner('lookup', () { + using((arena) { + final set = testDataSet(arena); + // ignore: iterable_contains_unrelated_type + expect(set.lookup(1), null); + expect( + set.lookup("1".toJString())?.toDartString(releaseOriginal: true), + "1", + ); + expect(set.lookup("4".toJString()..releasedBy(arena)), null); + }); + }); + testRunner('toSet', () { + using((arena) { + // Test if the set gets copied. + final set = testDataSet(arena); + final setCopy = set.toSet()..releasedBy(arena); + expect(set, setCopy); + set.add("4".toJString()..releasedBy(arena)); + expect(set, isNot(setCopy)); + }); + }); + testRunner('type hashCode, ==', () { + using((arena) { + final a = testDataSet(arena); + final b = testDataSet(arena); + expect(a.$type, b.$type); + expect(a.$type.hashCode, b.$type.hashCode); + final c = JSet.hash(JObject.type)..releasedBy(arena); + expect(a.$type, isNot(c.$type)); + expect(a.$type.hashCode, isNot(c.$type.hashCode)); + }); + }); +} diff --git a/pkgs/jni/test/jstring_test.dart b/pkgs/jni/test/jstring_test.dart new file mode 100644 index 000000000..c1a968c46 --- /dev/null +++ b/pkgs/jni/test/jstring_test.dart @@ -0,0 +1,51 @@ +// Copyright (c) 2023, 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. + +import 'dart:io'; + +import 'package:jni/jni.dart'; +import 'package:test/test.dart'; + +import 'test_util/test_util.dart'; + +void main() { + // Don't forget to initialize JNI. + if (!Platform.isAndroid) { + checkDylibIsUpToDate(); + Jni.spawnIfNotExists(dylibDir: "build/jni_libs", jvmOptions: ["-Xmx128m"]); + } + run(testRunner: test); +} + +void testStringBackAndForth(String str) { + final jstring = str.toJString(); + final dartString = jstring.toDartString(releaseOriginal: true); + expect(dartString, str); +} + +void run({required TestRunnerCallback testRunner}) { + group("String encoding tests", () { + testRunner('Long string back-and-forth', () { + testStringBackAndForth('1' * 8096); + }); + + testRunner('#278 UTF-8 bug', () { + testStringBackAndForth('🐬'); + }); + + testRunner('String containing null character', () { + final str = 'A${String.fromCharCode(0)}B'; + testStringBackAndForth(str); + }); + + testRunner('Zero length string', () { + testStringBackAndForth(''); + }); + }); + + testRunner('Inherited toString', () { + final s = 'hello'.toJString(); + expect(s.toString(), 'hello'); + }); +} diff --git a/pkgs/jni/test/load_test.dart b/pkgs/jni/test/load_test.dart new file mode 100644 index 000000000..d74a5fc5a --- /dev/null +++ b/pkgs/jni/test/load_test.dart @@ -0,0 +1,135 @@ +// 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. + +@Tags(['load_test']) + +import 'dart:io'; +import 'dart:ffi'; +import 'dart:math'; + +import 'package:ffi/ffi.dart'; +import 'package:test/test.dart'; + +import 'package:jni/jni.dart'; + +import 'test_util/test_util.dart'; + +const maxLongInJava = 9223372036854775807; + +/// Taken from +/// https://github.com/dart-lang/ffigen/blob/master/test/native_objc_test/automated_ref_count_test.dart +final executeInternalCommand = DynamicLibrary.process().lookupFunction< + Void Function(Pointer, Pointer), + void Function(Pointer, Pointer)>('Dart_ExecuteInternalCommand'); + +void doGC() { + final gcNow = "gc-now".toNativeUtf8(); + executeInternalCommand(gcNow.cast(), nullptr); + calloc.free(gcNow); +} + +void main() { + if (!Platform.isAndroid) { + checkDylibIsUpToDate(); + Jni.spawnIfNotExists(dylibDir: "build/jni_libs", jvmOptions: ["-Xmx128m"]); + } + run(testRunner: test); +} + +const k4 = 4 * 1024; +const k64 = 64 * 1024; +const k256 = 256 * 1024; + +const secureRandomSeedBound = 4294967296; + +JObject getSystemOut() => Jni.retrieveStaticField( + 'System', + 'out', + 'Ljava/io/PrintStream;', + ); + +final random = Random.secure(); + +JObject newRandom() => Jni.newInstance( + "java/util/Random", + "(J)V", + [random.nextInt(secureRandomSeedBound)], + ); + +void run({required TestRunnerCallback testRunner}) { + testRunner('Test 4K refs can be created in a row', () { + final list = []; + for (int i = 0; i < k4; i++) { + list.add(newRandom()); + } + for (final jobject in list) { + jobject.release(); + } + }); + + testRunner('Create and release 256K references in a loop using arena', () { + for (int i = 0; i < k256; i++) { + using((arena) { + final random = newRandom()..releasedBy(arena); + // The actual expect here does not matter. I am just being paranoid + // against assigning to `_` because compiler may optimize it. (It has + // side effect of calling FFI but still.) + expect(random.reference, isNot(nullptr)); + }); + } + }); + + testRunner('Create and release 256K references in a loop (explicit release)', + () { + for (int i = 0; i < k256; i++) { + final random = newRandom(); + expect(random.reference, isNot(nullptr)); + random.release(); + } + }); + + testRunner('Create and release 64K references, in batches of 256', () { + for (int i = 0; i < 64 * 4; i++) { + using((arena) { + for (int i = 0; i < 256; i++) { + final r = newRandom()..releasedBy(arena); + expect(r.reference, isNot(nullptr)); + } + }); + } + }); + + // We don't have a direct way to check if something creates JNI references. + // So we are checking if we can run this for large number of times. + testRunner('Verify a call returning primitive can be run any times', () { + final random = newRandom(); + final nextInt = random.getMethodID("nextInt", "()I"); + for (int i = 0; i < k256; i++) { + final rInt = random.callMethod(nextInt, []); + expect(rInt, isA()); + } + }); + + void testRefValidityAfterGC(int delayInSeconds) { + testRunner('Validate reference after GC & ${delayInSeconds}s sleep', () { + final random = newRandom(); + doGC(); + sleep(Duration(seconds: delayInSeconds)); + expect( + random.callMethodByName("nextInt", "()I", []), + isA(), + ); + expect( + Jni.env.GetObjectRefType(random.reference), + equals(JObjectRefType.JNIGlobalRefType), + ); + }); + } + + // Dart_ExecuteInternalCommand doesn't exist in Android. + if (!Platform.isAndroid) { + testRefValidityAfterGC(1); + testRefValidityAfterGC(10); + } +} diff --git a/pkgs/jni/test/test_util/test_util.dart b/pkgs/jni/test/test_util/test_util.dart new file mode 100644 index 000000000..07e711aa4 --- /dev/null +++ b/pkgs/jni/test/test_util/test_util.dart @@ -0,0 +1,38 @@ +// Copyright (c) 2023, 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. + +import 'dart:io'; + +import 'package:jni/src/build_util/build_util.dart'; + +typedef TestCaseCallback = void Function(); +typedef TestRunnerCallback = void Function( + String description, + TestCaseCallback test, +); + +final currentDir = Directory.current.uri; +final dllSuffix = + Platform.isWindows ? "dll" : (Platform.isMacOS ? "dylib" : "so"); +final dllPrefix = Platform.isWindows ? '' : 'lib'; +final dllPath = + currentDir.resolve("build/jni_libs/${dllPrefix}dartjni.$dllSuffix"); +final srcPath = currentDir.resolve("src/"); + +/// Fail if dartjni dll is stale. +void checkDylibIsUpToDate() { + final dllFile = File.fromUri(dllPath); + if (needsBuild(File.fromUri(dllPath), Directory.fromUri(srcPath))) { + final cause = dllFile.existsSync() + ? 'not up-to-date with source modifications' + : 'not built'; + var message = '\nFatal: dartjni.$dllSuffix is $cause. Please run ' + '`dart run jni:setup` and try again.'; + if (stderr.supportsAnsiEscapes) { + message = ansiRed + message + ansiDefault; + } + stderr.writeln(message); + exit(1); + } +} diff --git a/pkgs/jni/test/type_test.dart b/pkgs/jni/test/type_test.dart new file mode 100644 index 000000000..0ad8490af --- /dev/null +++ b/pkgs/jni/test/type_test.dart @@ -0,0 +1,327 @@ +// Copyright (c) 2023, 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. + +import 'dart:ffi'; +import 'dart:io'; + +import 'package:jni/jni.dart'; +import 'package:test/test.dart'; + +import 'test_util/test_util.dart'; + +// Mocking this type tree: +// JObject +// | \ +// A B +// / \ \ +// C D E +// / +// F + +class A extends JObject { + A.fromRef(super.reference) : super.fromRef(); + @override + JObjType get $type => $AType(); +} + +final class $AType extends JObjType { + @override + A fromRef(Pointer ref) { + return A.fromRef(ref); + } + + @override + String get signature => 'A'; + + @override + int get superCount => superType.superCount + 1; + + @override + JObjType get superType => JObject.type; + + @override + int get hashCode => ($AType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == $AType && other is $AType; + } +} + +class B extends JObject { + B.fromRef(super.reference) : super.fromRef(); + @override + JObjType get $type => $BType(); +} + +final class $BType extends JObjType { + @override + B fromRef(Pointer ref) { + return B.fromRef(ref); + } + + @override + String get signature => 'B'; + + @override + int get superCount => superType.superCount + 1; + + @override + JObjType get superType => JObject.type; + + @override + int get hashCode => ($BType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == $BType && other is $BType; + } +} + +class C extends A { + C.fromRef(super.reference) : super.fromRef(); + + @override + JObjType get $type => $CType(); +} + +final class $CType extends JObjType { + @override + C fromRef(Pointer ref) { + return C.fromRef(ref); + } + + @override + String get signature => 'C'; + + @override + int get superCount => superType.superCount + 1; + + @override + JObjType get superType => $AType(); + + @override + int get hashCode => ($CType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == $CType && other is $CType; + } +} + +class D extends A { + D.fromRef(super.reference) : super.fromRef(); + + @override + JObjType get $type => $DType(); +} + +final class $DType extends JObjType { + @override + D fromRef(Pointer ref) { + return D.fromRef(ref); + } + + @override + String get signature => 'D'; + + @override + int get superCount => superType.superCount + 1; + + @override + JObjType get superType => $AType(); + + @override + int get hashCode => ($DType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == $DType && other is $DType; + } +} + +class E extends B { + E.fromRef(super.reference) : super.fromRef(); + + @override + JObjType get $type => $EType(); +} + +final class $EType extends JObjType { + @override + E fromRef(Pointer ref) { + return E.fromRef(ref); + } + + @override + String get signature => 'E'; + + @override + int get superCount => superType.superCount + 1; + + @override + JObjType get superType => $BType(); + + @override + int get hashCode => ($EType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == $EType && other is $EType; + } +} + +class F extends C { + F.fromRef(super.reference) : super.fromRef(); + + @override + JObjType get $type => $FType(); +} + +final class $FType extends JObjType { + @override + F fromRef(Pointer ref) { + return F.fromRef(ref); + } + + @override + String get signature => 'F'; + + @override + int get superCount => superType.superCount + 1; + + @override + JObjType get superType => $CType(); + + @override + int get hashCode => ($FType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == $FType && other is $FType; + } +} + +void main() { + if (!Platform.isAndroid) { + checkDylibIsUpToDate(); + Jni.spawnIfNotExists(dylibDir: "build/jni_libs", jvmOptions: ["-Xmx128m"]); + } + run(testRunner: test); +} + +void run({required TestRunnerCallback testRunner}) { + testRunner('lowestCommonSuperType', () { + expect(lowestCommonSuperType([JObject.type]), JObject.type); + expect(lowestCommonSuperType([JString.type]), JString.type); + expect(lowestCommonSuperType([JObject.type, JObject.type]), JObject.type); + expect(lowestCommonSuperType([JString.type, JString.type]), JString.type); + expect(lowestCommonSuperType([JString.type, JArray.type(jlong.type)]), + JObject.type); + }); + + testRunner('Boxed types', () { + expect( + lowestCommonSuperType([ + JByte.type, + JInteger.type, + JLong.type, + JShort.type, + JDouble.type, + JFloat.type, + ]), + JNumber.type, + ); + expect(lowestCommonSuperType([JByte.type, JBoolean.type]), JObject.type); + }); + + testRunner('array types', () { + using((arena) { + expect( + lowestCommonSuperType([ + JArray.type(jint.type), + JArray.type(jint.type), + ]), + JArray.type(jint.type), + ); + expect( + lowestCommonSuperType([ + JArray.type(JObject.type), + JArray.type(JObject.type), + ]), + JArray.type(JObject.type), + ); + expect( + lowestCommonSuperType([ + JArray.type(JObject.type), + JArray.type(jint.type), + ]), + JObject.type, + ); + }); + }); + + testRunner('util types', () { + using((arena) { + expect( + lowestCommonSuperType([ + JList.type(JObject.type), + JList.type(JObject.type), + ]), + JList.type(JObject.type), + ); + expect( + lowestCommonSuperType([ + JList.type(JObject.type), + JList.type(JString.type), + ]), + JObject.type, + ); + expect( + lowestCommonSuperType([ + JList.type(JObject.type), + JMap.type(JObject.type, JObject.type), + ]), + JObject.type, + ); + expect( + lowestCommonSuperType([ + JSet.type(JObject.type), + JIterator.type(JObject.type), + ]), + JObject.type, + ); + expect( + lowestCommonSuperType([ + JByteBuffer.type, + JBuffer.type, + ]), + JBuffer.type, + ); + }); + }); + + testRunner('Mocked type tree', () { + // As a reminder, this is how the type tree looks like: + // JObject + // | \ + // A B + // / \ \ + // C D E + // / + // F + expect(lowestCommonSuperType([$AType(), $BType()]), const JObjectType()); + expect(lowestCommonSuperType([$CType(), $BType()]), const JObjectType()); + expect(lowestCommonSuperType([$FType(), $BType()]), const JObjectType()); + expect(lowestCommonSuperType([$EType(), $CType(), $FType()]), + const JObjectType()); + + expect(lowestCommonSuperType([$CType(), $DType()]), $AType()); + expect(lowestCommonSuperType([$FType(), $DType()]), $AType()); + expect(lowestCommonSuperType([$FType(), $CType(), $DType()]), $AType()); + + expect(lowestCommonSuperType([$EType(), $BType()]), $BType()); + expect(lowestCommonSuperType([$BType(), $BType()]), $BType()); + }); +} diff --git a/pkgs/jni/third_party/jni.h b/pkgs/jni/third_party/jni.h new file mode 100644 index 000000000..b71105eaf --- /dev/null +++ b/pkgs/jni/third_party/jni.h @@ -0,0 +1,1490 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * JNI specification, as defined by Sun: + * http://java.sun.com/javase/6/docs/technotes/guides/jni/spec/jniTOC.html + * + * Everything here is expected to be VM-neutral. + */ + +/* ANNOTATED COPY FOR DART JNI LIBRARY */ + +#pragma once + +#include +#include + +/* Primitive types that match up with Java equivalents. */ +typedef uint8_t jboolean; /* unsigned 8 bits */ +typedef int8_t jbyte; /* signed 8 bits */ +typedef uint16_t jchar; /* unsigned 16 bits */ +typedef int16_t jshort; /* signed 16 bits */ +typedef int32_t jint; /* signed 32 bits */ +typedef int64_t jlong; /* signed 64 bits */ +typedef float jfloat; /* 32-bit IEEE 754 */ +typedef double jdouble; /* 64-bit IEEE 754 */ + +/* "cardinal indices and sizes" */ +typedef jint jsize; + +#ifdef __cplusplus +/* + * Reference types, in C++ + */ +class _jobject +{ +}; +class _jclass : public _jobject +{ +}; +class _jstring : public _jobject +{ +}; +class _jarray : public _jobject +{ +}; +class _jobjectArray : public _jarray +{ +}; +class _jbooleanArray : public _jarray +{ +}; +class _jbyteArray : public _jarray +{ +}; +class _jcharArray : public _jarray +{ +}; +class _jshortArray : public _jarray +{ +}; +class _jintArray : public _jarray +{ +}; +class _jlongArray : public _jarray +{ +}; +class _jfloatArray : public _jarray +{ +}; +class _jdoubleArray : public _jarray +{ +}; +class _jthrowable : public _jobject +{ +}; + +typedef _jobject *jobject; +typedef _jclass *jclass; +typedef _jstring *jstring; +typedef _jarray *jarray; +typedef _jobjectArray *jobjectArray; +typedef _jbooleanArray *jbooleanArray; +typedef _jbyteArray *jbyteArray; +typedef _jcharArray *jcharArray; +typedef _jshortArray *jshortArray; +typedef _jintArray *jintArray; +typedef _jlongArray *jlongArray; +typedef _jfloatArray *jfloatArray; +typedef _jdoubleArray *jdoubleArray; +typedef _jthrowable *jthrowable; +typedef _jobject *jweak; + +#else /* not __cplusplus */ + +/* + * Reference types, in C. + */ +typedef void *jobject; +typedef jobject jclass; +typedef jobject jstring; +typedef jobject jarray; +typedef jarray jobjectArray; +typedef jarray jbooleanArray; +typedef jarray jbyteArray; +typedef jarray jcharArray; +typedef jarray jshortArray; +typedef jarray jintArray; +typedef jarray jlongArray; +typedef jarray jfloatArray; +typedef jarray jdoubleArray; +typedef jobject jthrowable; +typedef jobject jweak; + +#endif /* not __cplusplus */ + +struct _jfieldID; /* opaque structure */ +typedef struct _jfieldID *jfieldID; /* field IDs */ + +struct _jmethodID; /* opaque structure */ +typedef struct _jmethodID *jmethodID; /* method IDs */ + +struct JNIInvokeInterface; + +typedef union jvalue +{ + jboolean z; + jbyte b; + jchar c; + jshort s; + jint i; + jlong j; + jfloat f; + jdouble d; + jobject l; +} jvalue; + +typedef enum jobjectRefType +{ + JNIInvalidRefType = 0, + JNILocalRefType = 1, + JNIGlobalRefType = 2, + JNIWeakGlobalRefType = 3 +} jobjectRefType; + +typedef struct +{ + const char *name; + const char *signature; + void *fnPtr; +} JNINativeMethod; + +struct _JNIEnv; +struct _JavaVM; +typedef const struct JNINativeInterface *C_JNIEnv; + +#if defined(__cplusplus) +typedef _JNIEnv JNIEnv; +typedef _JavaVM JavaVM; +#else +typedef const struct JNINativeInterface *JNIEnv; +typedef const struct JNIInvokeInterface *JavaVM; +#endif + +/* + * Table of interface function pointers. + */ +struct JNINativeInterface +{ + void *reserved0; + void *reserved1; + void *reserved2; + void *reserved3; + + jint (*GetVersion)(JNIEnv *env); + jclass (*DefineClass)(JNIEnv *env, const char *name, jobject loader, const jbyte *buf, + jsize bufLen); + jclass (*FindClass)(JNIEnv *env, const char *name); + + jmethodID (*FromReflectedMethod)(JNIEnv *env, jobject method); + jfieldID (*FromReflectedField)(JNIEnv *env, jobject field); + + /* spec doesn't show jboolean parameter */ + + jobject (*ToReflectedMethod)(JNIEnv *env, jclass cls, jmethodID methodId, jboolean isStatic); + + jclass (*GetSuperclass)(JNIEnv *env, jclass clazz); + jboolean (*IsAssignableFrom)(JNIEnv *env, jclass clazz1, jclass clazz2); + + /* spec doesn't show jboolean parameter */ + + jobject (*ToReflectedField)(JNIEnv *env, jclass cls, jfieldID fieldID, jboolean isStatic); + + jint (*Throw)(JNIEnv *env, jthrowable obj); + jint (*ThrowNew)(JNIEnv *env, jclass clazz, const char *message); + jthrowable (*ExceptionOccurred)(JNIEnv *env); + void (*ExceptionDescribe)(JNIEnv *env); + void (*ExceptionClear)(JNIEnv *env); + void (*FatalError)(JNIEnv *env, const char *msg); + + jint (*PushLocalFrame)(JNIEnv *env, jint capacity); + jobject (*PopLocalFrame)(JNIEnv *env, jobject result); + + jobject (*NewGlobalRef)(JNIEnv *env, jobject obj); + void (*DeleteGlobalRef)(JNIEnv *env, jobject globalRef); + void (*DeleteLocalRef)(JNIEnv *env, jobject localRef); + jboolean (*IsSameObject)(JNIEnv *env, jobject ref1, jobject ref2); + + jobject (*NewLocalRef)(JNIEnv *env, jobject obj); + jint (*EnsureLocalCapacity)(JNIEnv *env, jint capacity); + + jobject (*AllocObject)(JNIEnv *env, jclass clazz); + jobject (*NewObject)(JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jobject (*NewObjectV)(JNIEnv *, jclass, jmethodID, void *); + jobject (*NewObjectA)(JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + + jclass (*GetObjectClass)(JNIEnv *env, jobject obj); + jboolean (*IsInstanceOf)(JNIEnv *env, jobject obj, jclass clazz); + jmethodID (*GetMethodID)(JNIEnv *env, jclass clazz, const char *name, const char *sig); + + jobject (*CallObjectMethod)(JNIEnv *env, jobject obj, jmethodID methodID, ...); + jobject (*CallObjectMethodV)(JNIEnv *, jobject, jmethodID, void *); + jobject (*CallObjectMethodA)(JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); + jboolean (*CallBooleanMethod)(JNIEnv *env, jobject obj, jmethodID methodID, ...); + jboolean (*CallBooleanMethodV)(JNIEnv *, jobject, jmethodID, void *); + jboolean (*CallBooleanMethodA)(JNIEnv *env, jobject obj, jmethodID methodId, const jvalue *args); + jbyte (*CallByteMethod)(JNIEnv *env, jobject obj, jmethodID methodID, ...); + jbyte (*CallByteMethodV)(JNIEnv *, jobject, jmethodID, void *); + jbyte (*CallByteMethodA)(JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); + jchar (*CallCharMethod)(JNIEnv *env, jobject obj, jmethodID methodID, ...); + jchar (*CallCharMethodV)(JNIEnv *, jobject, jmethodID, void *); + jchar (*CallCharMethodA)(JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); + jshort (*CallShortMethod)(JNIEnv *env, jobject obj, jmethodID methodID, ...); + jshort (*CallShortMethodV)(JNIEnv *, jobject, jmethodID, void *); + jshort (*CallShortMethodA)(JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); + jint (*CallIntMethod)(JNIEnv *env, jobject obj, jmethodID methodID, ...); + jint (*CallIntMethodV)(JNIEnv *, jobject, jmethodID, void *); + jint (*CallIntMethodA)(JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); + jlong (*CallLongMethod)(JNIEnv *env, jobject obj, jmethodID methodID, ...); + jlong (*CallLongMethodV)(JNIEnv *, jobject, jmethodID, void *); + jlong (*CallLongMethodA)(JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); + jfloat (*CallFloatMethod)(JNIEnv *env, jobject obj, jmethodID methodID, ...); + jfloat (*CallFloatMethodV)(JNIEnv *, jobject, jmethodID, void *); + jfloat (*CallFloatMethodA)(JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); + jdouble (*CallDoubleMethod)(JNIEnv *env, jobject obj, jmethodID methodID, ...); + jdouble (*CallDoubleMethodV)(JNIEnv *, jobject, jmethodID, void *); + jdouble (*CallDoubleMethodA)(JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); + void (*CallVoidMethod)(JNIEnv *env, jobject obj, jmethodID methodID, ...); + void (*CallVoidMethodV)(JNIEnv *, jobject, jmethodID, void *); + void (*CallVoidMethodA)(JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); + + jobject (*CallNonvirtualObjectMethod)(JNIEnv *env, jobject obj, jclass clazz, + jmethodID methodID, ...); + jobject (*CallNonvirtualObjectMethodV)(JNIEnv *, jobject, jclass, + jmethodID, void *); + jobject (*CallNonvirtualObjectMethodA)(JNIEnv *env, jobject obj, jclass clazz, + jmethodID methodID, const jvalue *args); + jboolean (*CallNonvirtualBooleanMethod)(JNIEnv *env, jobject obj, jclass clazz, + jmethodID methodID, ...); + jboolean (*CallNonvirtualBooleanMethodV)(JNIEnv *, jobject, jclass, + jmethodID, void *); + jboolean (*CallNonvirtualBooleanMethodA)(JNIEnv *env, jobject obj, jclass clazz, + jmethodID methodID, const jvalue *args); + jbyte (*CallNonvirtualByteMethod)(JNIEnv *env, jobject obj, jclass clazz, + jmethodID methodID, ...); + jbyte (*CallNonvirtualByteMethodV)(JNIEnv *, jobject, jclass, + jmethodID, void *); + jbyte (*CallNonvirtualByteMethodA)(JNIEnv *env, jobject obj, jclass clazz, + jmethodID methodID, const jvalue *args); + jchar (*CallNonvirtualCharMethod)(JNIEnv *env, jobject obj, jclass clazz, + jmethodID methodID, ...); + jchar (*CallNonvirtualCharMethodV)(JNIEnv *, jobject, jclass, + jmethodID, void *); + jchar (*CallNonvirtualCharMethodA)(JNIEnv *env, jobject obj, jclass clazz, + jmethodID methodID, const jvalue *args); + jshort (*CallNonvirtualShortMethod)(JNIEnv *env, jobject obj, jclass clazz, + jmethodID methodID, ...); + jshort (*CallNonvirtualShortMethodV)(JNIEnv *, jobject, jclass, + jmethodID, void *); + jshort (*CallNonvirtualShortMethodA)(JNIEnv *env, jobject obj, jclass clazz, + jmethodID methodID, const jvalue *args); + jint (*CallNonvirtualIntMethod)(JNIEnv *env, jobject obj, jclass clazz, + jmethodID methodID, ...); + jint (*CallNonvirtualIntMethodV)(JNIEnv *, jobject, jclass, + jmethodID, void *); + jint (*CallNonvirtualIntMethodA)(JNIEnv *env, jobject obj, jclass clazz, + jmethodID methodID, const jvalue *args); + jlong (*CallNonvirtualLongMethod)(JNIEnv *env, jobject obj, jclass clazz, + jmethodID methodID, ...); + jlong (*CallNonvirtualLongMethodV)(JNIEnv *, jobject, jclass, + jmethodID, void *); + jlong (*CallNonvirtualLongMethodA)(JNIEnv *env, jobject obj, jclass clazz, + jmethodID methodID, const jvalue *args); + jfloat (*CallNonvirtualFloatMethod)(JNIEnv *env, jobject obj, jclass clazz, + jmethodID methodID, ...); + jfloat (*CallNonvirtualFloatMethodV)(JNIEnv *, jobject, jclass, + jmethodID, void *); + jfloat (*CallNonvirtualFloatMethodA)(JNIEnv *env, jobject obj, jclass clazz, + jmethodID methodID, const jvalue *args); + jdouble (*CallNonvirtualDoubleMethod)(JNIEnv *env, jobject obj, jclass clazz, + jmethodID methodID, ...); + jdouble (*CallNonvirtualDoubleMethodV)(JNIEnv *, jobject, jclass, + jmethodID, void *); + jdouble (*CallNonvirtualDoubleMethodA)(JNIEnv *env, jobject obj, jclass clazz, + jmethodID methodID, const jvalue *args); + void (*CallNonvirtualVoidMethod)(JNIEnv *env, jobject obj, jclass clazz, + jmethodID methodID, ...); + void (*CallNonvirtualVoidMethodV)(JNIEnv *, jobject, jclass, + jmethodID, void *); + void (*CallNonvirtualVoidMethodA)(JNIEnv *env, jobject obj, jclass clazz, + jmethodID methodID, const jvalue *args); + + jfieldID (*GetFieldID)(JNIEnv *env, jclass clazz, const char *name, const char *sig); + + jobject (*GetObjectField)(JNIEnv *env, jobject obj, jfieldID fieldID); + jboolean (*GetBooleanField)(JNIEnv *env, jobject obj, jfieldID fieldID); + jbyte (*GetByteField)(JNIEnv *env, jobject obj, jfieldID fieldID); + jchar (*GetCharField)(JNIEnv *env, jobject obj, jfieldID fieldID); + jshort (*GetShortField)(JNIEnv *env, jobject obj, jfieldID fieldID); + jint (*GetIntField)(JNIEnv *env, jobject obj, jfieldID fieldID); + jlong (*GetLongField)(JNIEnv *env, jobject obj, jfieldID fieldID); + jfloat (*GetFloatField)(JNIEnv *env, jobject obj, jfieldID fieldID); + jdouble (*GetDoubleField)(JNIEnv *env, jobject obj, jfieldID fieldID); + + void (*SetObjectField)(JNIEnv *env, jobject obj, jfieldID fieldID, jobject val); + void (*SetBooleanField)(JNIEnv *env, jobject obj, jfieldID fieldID, jboolean val); + void (*SetByteField)(JNIEnv *env, jobject obj, jfieldID fieldID, jbyte val); + void (*SetCharField)(JNIEnv *env, jobject obj, jfieldID fieldID, jchar val); + void (*SetShortField)(JNIEnv *env, jobject obj, jfieldID fieldID, jshort val); + void (*SetIntField)(JNIEnv *env, jobject obj, jfieldID fieldID, jint val); + void (*SetLongField)(JNIEnv *env, jobject obj, jfieldID fieldID, jlong val); + void (*SetFloatField)(JNIEnv *env, jobject obj, jfieldID fieldID, jfloat val); + void (*SetDoubleField)(JNIEnv *env, jobject obj, jfieldID fieldID, jdouble val); + + jmethodID (*GetStaticMethodID)(JNIEnv *env, jclass clazz, const char *name, const char *sig); + + jobject (*CallStaticObjectMethod)(JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jobject (*CallStaticObjectMethodV)(JNIEnv *, jclass, jmethodID, void *); + jobject (*CallStaticObjectMethodA)(JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + jboolean (*CallStaticBooleanMethod)(JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jboolean (*CallStaticBooleanMethodV)(JNIEnv *, jclass, jmethodID, + void *); + jboolean (*CallStaticBooleanMethodA)(JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + jbyte (*CallStaticByteMethod)(JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jbyte (*CallStaticByteMethodV)(JNIEnv *, jclass, jmethodID, void *); + jbyte (*CallStaticByteMethodA)(JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + jchar (*CallStaticCharMethod)(JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jchar (*CallStaticCharMethodV)(JNIEnv *, jclass, jmethodID, void *); + jchar (*CallStaticCharMethodA)(JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + jshort (*CallStaticShortMethod)(JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jshort (*CallStaticShortMethodV)(JNIEnv *, jclass, jmethodID, void *); + jshort (*CallStaticShortMethodA)(JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + jint (*CallStaticIntMethod)(JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jint (*CallStaticIntMethodV)(JNIEnv *, jclass, jmethodID, void *); + jint (*CallStaticIntMethodA)(JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + jlong (*CallStaticLongMethod)(JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jlong (*CallStaticLongMethodV)(JNIEnv *, jclass, jmethodID, void *); + jlong (*CallStaticLongMethodA)(JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + jfloat (*CallStaticFloatMethod)(JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jfloat (*CallStaticFloatMethodV)(JNIEnv *, jclass, jmethodID, void *); + jfloat (*CallStaticFloatMethodA)(JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + jdouble (*CallStaticDoubleMethod)(JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jdouble (*CallStaticDoubleMethodV)(JNIEnv *, jclass, jmethodID, void *); + jdouble (*CallStaticDoubleMethodA)(JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + void (*CallStaticVoidMethod)(JNIEnv *env, jclass clazz, jmethodID methodID, ...); + void (*CallStaticVoidMethodV)(JNIEnv *, jclass, jmethodID, void *); + void (*CallStaticVoidMethodA)(JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + + jfieldID (*GetStaticFieldID)(JNIEnv *env, jclass clazz, const char *name, + const char *sig); + + jobject (*GetStaticObjectField)(JNIEnv *env, jclass clazz, jfieldID fieldID); + jboolean (*GetStaticBooleanField)(JNIEnv *env, jclass clazz, jfieldID fieldID); + jbyte (*GetStaticByteField)(JNIEnv *env, jclass clazz, jfieldID fieldID); + jchar (*GetStaticCharField)(JNIEnv *env, jclass clazz, jfieldID fieldID); + jshort (*GetStaticShortField)(JNIEnv *env, jclass clazz, jfieldID fieldID); + jint (*GetStaticIntField)(JNIEnv *env, jclass clazz, jfieldID fieldID); + jlong (*GetStaticLongField)(JNIEnv *env, jclass clazz, jfieldID fieldID); + jfloat (*GetStaticFloatField)(JNIEnv *env, jclass clazz, jfieldID fieldID); + jdouble (*GetStaticDoubleField)(JNIEnv *env, jclass clazz, jfieldID fieldID); + + void (*SetStaticObjectField)(JNIEnv *env, jclass clazz, jfieldID fieldID, jobject val); + void (*SetStaticBooleanField)(JNIEnv *env, jclass clazz, jfieldID fieldID, jboolean val); + void (*SetStaticByteField)(JNIEnv *env, jclass clazz, jfieldID fieldID, jbyte val); + void (*SetStaticCharField)(JNIEnv *env, jclass clazz, jfieldID fieldID, jchar val); + void (*SetStaticShortField)(JNIEnv *env, jclass clazz, jfieldID fieldID, jshort val); + void (*SetStaticIntField)(JNIEnv *env, jclass clazz, jfieldID fieldID, jint val); + void (*SetStaticLongField)(JNIEnv *env, jclass clazz, jfieldID fieldID, jlong val); + void (*SetStaticFloatField)(JNIEnv *env, jclass clazz, jfieldID fieldID, jfloat val); + void (*SetStaticDoubleField)(JNIEnv *env, jclass clazz, jfieldID fieldID, jdouble val); + + jstring (*NewString)(JNIEnv *env, const jchar *unicodeChars, jsize len); + jsize (*GetStringLength)(JNIEnv *env, jstring string); + const jchar *(*GetStringChars)(JNIEnv *env, jstring string, jboolean *isCopy); + void (*ReleaseStringChars)(JNIEnv *env, jstring string, const jchar *isCopy); + jstring (*NewStringUTF)(JNIEnv *env, const char *bytes); + jsize (*GetStringUTFLength)(JNIEnv *env, jstring string); + const char *(*GetStringUTFChars)(JNIEnv *env, jstring string, jboolean *isCopy); + void (*ReleaseStringUTFChars)(JNIEnv *env, jstring string, const char *utf); + jsize (*GetArrayLength)(JNIEnv *env, jarray array); + jobjectArray (*NewObjectArray)(JNIEnv *env, jsize length, jclass elementClass, jobject initialElement); + jobject (*GetObjectArrayElement)(JNIEnv *env, jobjectArray array, jsize index); + void (*SetObjectArrayElement)(JNIEnv *env, jobjectArray array, jsize index, jobject val); + + jbooleanArray (*NewBooleanArray)(JNIEnv *env, jsize length); + jbyteArray (*NewByteArray)(JNIEnv *env, jsize length); + jcharArray (*NewCharArray)(JNIEnv *env, jsize length); + jshortArray (*NewShortArray)(JNIEnv *env, jsize length); + jintArray (*NewIntArray)(JNIEnv *env, jsize length); + jlongArray (*NewLongArray)(JNIEnv *env, jsize length); + jfloatArray (*NewFloatArray)(JNIEnv *env, jsize length); + jdoubleArray (*NewDoubleArray)(JNIEnv *env, jsize length); + + jboolean *(*GetBooleanArrayElements)(JNIEnv *env, jbooleanArray array, jboolean *isCopy); + jbyte *(*GetByteArrayElements)(JNIEnv *env, jbyteArray array, jboolean *isCopy); + jchar *(*GetCharArrayElements)(JNIEnv *env, jcharArray array, jboolean *isCopy); + jshort *(*GetShortArrayElements)(JNIEnv *env, jshortArray array, jboolean *isCopy); + jint *(*GetIntArrayElements)(JNIEnv *env, jintArray array, jboolean *isCopy); + jlong *(*GetLongArrayElements)(JNIEnv *env, jlongArray array, jboolean *isCopy); + jfloat *(*GetFloatArrayElements)(JNIEnv *env, jfloatArray array, jboolean *isCopy); + jdouble *(*GetDoubleArrayElements)(JNIEnv *env, jdoubleArray array, jboolean *isCopy); + + void (*ReleaseBooleanArrayElements)(JNIEnv *env, jbooleanArray array, + jboolean *elems, jint mode); + void (*ReleaseByteArrayElements)(JNIEnv *env, jbyteArray array, + jbyte *elems, jint mode); + void (*ReleaseCharArrayElements)(JNIEnv *env, jcharArray array, + jchar *elems, jint mode); + void (*ReleaseShortArrayElements)(JNIEnv *env, jshortArray array, + jshort *elems, jint mode); + void (*ReleaseIntArrayElements)(JNIEnv *env, jintArray array, + jint *elems, jint mode); + void (*ReleaseLongArrayElements)(JNIEnv *env, jlongArray array, + jlong *elems, jint mode); + void (*ReleaseFloatArrayElements)(JNIEnv *env, jfloatArray array, + jfloat *elems, jint mode); + void (*ReleaseDoubleArrayElements)(JNIEnv *env, jdoubleArray array, + jdouble *elems, jint mode); + + void (*GetBooleanArrayRegion)(JNIEnv *env, jbooleanArray array, + jsize start, jsize len, jboolean *buf); + void (*GetByteArrayRegion)(JNIEnv *env, jbyteArray array, + jsize start, jsize len, jbyte *buf); + void (*GetCharArrayRegion)(JNIEnv *env, jcharArray array, + jsize start, jsize len, jchar *buf); + void (*GetShortArrayRegion)(JNIEnv *env, jshortArray array, + jsize start, jsize len, jshort *buf); + void (*GetIntArrayRegion)(JNIEnv *env, jintArray array, + jsize start, jsize len, jint *buf); + void (*GetLongArrayRegion)(JNIEnv *env, jlongArray array, + jsize start, jsize len, jlong *buf); + void (*GetFloatArrayRegion)(JNIEnv *env, jfloatArray array, + jsize start, jsize len, jfloat *buf); + void (*GetDoubleArrayRegion)(JNIEnv *env, jdoubleArray array, + jsize start, jsize len, jdouble *buf); + + /* spec shows these without const; some jni.h do, some don't */ + void (*SetBooleanArrayRegion)(JNIEnv *env, jbooleanArray array, + jsize start, jsize len, const jboolean *buf); + void (*SetByteArrayRegion)(JNIEnv *env, jbyteArray array, + jsize start, jsize len, const jbyte *buf); + void (*SetCharArrayRegion)(JNIEnv *env, jcharArray array, + jsize start, jsize len, const jchar *buf); + void (*SetShortArrayRegion)(JNIEnv *env, jshortArray array, + jsize start, jsize len, const jshort *buf); + void (*SetIntArrayRegion)(JNIEnv *env, jintArray array, + jsize start, jsize len, const jint *buf); + void (*SetLongArrayRegion)(JNIEnv *env, jlongArray array, + jsize start, jsize len, const jlong *buf); + void (*SetFloatArrayRegion)(JNIEnv *env, jfloatArray array, + jsize start, jsize len, const jfloat *buf); + void (*SetDoubleArrayRegion)(JNIEnv *env, jdoubleArray array, + jsize start, jsize len, const jdouble *buf); + + jint (*RegisterNatives)(JNIEnv *env, jclass clazz, const JNINativeMethod *methods, + jint nMethods); + jint (*UnregisterNatives)(JNIEnv *env, jclass clazz); + jint (*MonitorEnter)(JNIEnv *env, jobject obj); + jint (*MonitorExit)(JNIEnv *env, jobject obj); + jint (*GetJavaVM)(JNIEnv *env, JavaVM **vm); + + void (*GetStringRegion)(JNIEnv *env, jstring str, jsize start, jsize len, jchar *buf); + void (*GetStringUTFRegion)(JNIEnv *env, jstring str, jsize start, jsize len, char *buf); + + void *(*GetPrimitiveArrayCritical)(JNIEnv *env, jarray array, jboolean *isCopy); + void (*ReleasePrimitiveArrayCritical)(JNIEnv *env, jarray array, void *carray, jint mode); + + const jchar *(*GetStringCritical)(JNIEnv *env, jstring str, jboolean *isCopy); + void (*ReleaseStringCritical)(JNIEnv *env, jstring str, const jchar *carray); + + jweak (*NewWeakGlobalRef)(JNIEnv *env, jobject obj); + void (*DeleteWeakGlobalRef)(JNIEnv *env, jweak obj); + + jboolean (*ExceptionCheck)(JNIEnv *env); + + jobject (*NewDirectByteBuffer)(JNIEnv *env, void *address, jlong capacity); + void *(*GetDirectBufferAddress)(JNIEnv *env, jobject buf); + jlong (*GetDirectBufferCapacity)(JNIEnv *env, jobject buf); + + /* added in JNI 1.6 */ + jobjectRefType (*GetObjectRefType)(JNIEnv *env, jobject obj); +}; + +/* + * C++ object wrapper. + * + * This is usually overlaid on a C struct whose first element is a + * JNINativeInterface*. We rely somewhat on compiler behavior. + */ +struct _JNIEnv +{ + /* do not rename this; it does not seem to be entirely opaque */ + const struct JNINativeInterface *functions; + +#if defined(__cplusplus) + + jint GetVersion() + { + return functions->GetVersion(this); + } + + jclass DefineClass(const char *name, jobject loader, const jbyte *buf, + jsize bufLen) + { + return functions->DefineClass(this, name, loader, buf, bufLen); + } + + jclass FindClass(const char *name) + { + return functions->FindClass(this, name); + } + + jmethodID FromReflectedMethod(jobject method) + { + return functions->FromReflectedMethod(this, method); + } + + jfieldID FromReflectedField(jobject field) + { + return functions->FromReflectedField(this, field); + } + + jobject ToReflectedMethod(jclass cls, jmethodID methodID, jboolean isStatic) + { + return functions->ToReflectedMethod(this, cls, methodID, isStatic); + } + + jclass GetSuperclass(jclass clazz) + { + return functions->GetSuperclass(this, clazz); + } + + jboolean IsAssignableFrom(jclass clazz1, jclass clazz2) + { + return functions->IsAssignableFrom(this, clazz1, clazz2); + } + + jobject ToReflectedField(jclass cls, jfieldID fieldID, jboolean isStatic) + { + return functions->ToReflectedField(this, cls, fieldID, isStatic); + } + + jint Throw(jthrowable obj) + { + return functions->Throw(this, obj); + } + + jint ThrowNew(jclass clazz, const char *message) + { + return functions->ThrowNew(this, clazz, message); + } + + jthrowable ExceptionOccurred() + { + return functions->ExceptionOccurred(this); + } + + void ExceptionDescribe() + { + functions->ExceptionDescribe(this); + } + + void ExceptionClear() + { + functions->ExceptionClear(this); + } + + void FatalError(const char *msg) + { + functions->FatalError(this, msg); + } + + jint PushLocalFrame(jint capacity) + { + return functions->PushLocalFrame(this, capacity); + } + + jobject PopLocalFrame(jobject result) + { + return functions->PopLocalFrame(this, result); + } + + jobject NewGlobalRef(jobject obj) + { + return functions->NewGlobalRef(this, obj); + } + + void DeleteGlobalRef(jobject globalRef) + { + functions->DeleteGlobalRef(this, globalRef); + } + + void DeleteLocalRef(jobject localRef) + { + functions->DeleteLocalRef(this, localRef); + } + + jboolean IsSameObject(jobject ref1, jobject ref2) + { + return functions->IsSameObject(this, ref1, ref2); + } + + jobject NewLocalRef(jobject obj) + { + return functions->NewLocalRef(this, ref); + } + + jint EnsureLocalCapacity(jint capacity) + { + return functions->EnsureLocalCapacity(this, capacity); + } + + jobject AllocObject(jclass clazz) + { + return functions->AllocObject(this, clazz); + } + + jobject NewObject(jclass clazz, jmethodID methodID, ...) + { + va_list args; + va_start(args, methodID); + jobject result = functions->NewObjectV(this, clazz, methodID, args); + va_end(args); + return result; + } + + jobject NewObjectV(jclass clazz, jmethodID methodID, va_list args) + { + return functions->NewObjectV(this, clazz, methodID, args); + } + + jobject NewObjectA(jclass clazz, jmethodID methodID, const jvalue *args) + { + return functions->NewObjectA(this, clazz, methodID, args); + } + + jclass GetObjectClass(jobject obj) + { + return functions->GetObjectClass(this, obj); + } + + jboolean IsInstanceOf(jobject obj, jclass clazz) + { + return functions->IsInstanceOf(this, obj, clazz); + } + + jmethodID GetMethodID(jclass clazz, const char *name, const char *sig) + { + return functions->GetMethodID(this, clazz, name, sig); + } + +#define CALL_TYPE_METHOD(_jtype, _jname) \ + _jtype Call##_jname##Method(jobject obj, jmethodID methodID, ...) \ + { \ + _jtype result; \ + va_list args; \ + va_start(args, methodID); \ + result = functions->Call##_jname##MethodV(this, obj, methodID, \ + args); \ + va_end(args); \ + return result; \ + } +#define CALL_TYPE_METHODV(_jtype, _jname) \ + _jtype Call##_jname##MethodV(jobject obj, jmethodID methodID, \ + va_list args) \ + { \ + return functions->Call##_jname##MethodV(this, obj, methodID, args); \ + } +#define CALL_TYPE_METHODA(_jtype, _jname) \ + _jtype Call##_jname##MethodA(jobject obj, jmethodID methodID, \ + const jvalue *args) \ + { \ + return functions->Call##_jname##MethodA(this, obj, methodID, args); \ + } + +#define CALL_TYPE(_jtype, _jname) \ + CALL_TYPE_METHOD(_jtype, _jname) \ + CALL_TYPE_METHODV(_jtype, _jname) \ + CALL_TYPE_METHODA(_jtype, _jname) + + CALL_TYPE(jobject, Object) + CALL_TYPE(jboolean, Boolean) + CALL_TYPE(jbyte, Byte) + CALL_TYPE(jchar, Char) + CALL_TYPE(jshort, Short) + CALL_TYPE(jint, Int) + CALL_TYPE(jlong, Long) + CALL_TYPE(jfloat, Float) + CALL_TYPE(jdouble, Double) + + void CallVoidMethod(jobject obj, jmethodID methodID, ...) + { + va_list args; + va_start(args, methodID); + functions->CallVoidMethodV(this, obj, methodID, args); + va_end(args); + } + void CallVoidMethodV(jobject obj, jmethodID methodID, va_list args) + { + functions->CallVoidMethodV(this, obj, methodID, args); + } + void CallVoidMethodA(jobject obj, jmethodID methodID, const jvalue *args) + { + functions->CallVoidMethodA(this, obj, methodID, args); + } + +#define CALL_NONVIRT_TYPE_METHOD(_jtype, _jname) \ + _jtype CallNonvirtual##_jname##Method(jobject obj, jclass clazz, \ + jmethodID methodID, ...) \ + { \ + _jtype result; \ + va_list args; \ + va_start(args, methodID); \ + result = functions->CallNonvirtual##_jname##MethodV(this, obj, \ + clazz, methodID, args); \ + va_end(args); \ + return result; \ + } +#define CALL_NONVIRT_TYPE_METHODV(_jtype, _jname) \ + _jtype CallNonvirtual##_jname##MethodV(jobject obj, jclass clazz, \ + jmethodID methodID, va_list args) \ + { \ + return functions->CallNonvirtual##_jname##MethodV(this, obj, clazz, \ + methodID, args); \ + } +#define CALL_NONVIRT_TYPE_METHODA(_jtype, _jname) \ + _jtype CallNonvirtual##_jname##MethodA(jobject obj, jclass clazz, \ + jmethodID methodID, const jvalue *args) \ + { \ + return functions->CallNonvirtual##_jname##MethodA(this, obj, clazz, \ + methodID, args); \ + } + +#define CALL_NONVIRT_TYPE(_jtype, _jname) \ + CALL_NONVIRT_TYPE_METHOD(_jtype, _jname) \ + CALL_NONVIRT_TYPE_METHODV(_jtype, _jname) \ + CALL_NONVIRT_TYPE_METHODA(_jtype, _jname) + + CALL_NONVIRT_TYPE(jobject, Object) + CALL_NONVIRT_TYPE(jboolean, Boolean) + CALL_NONVIRT_TYPE(jbyte, Byte) + CALL_NONVIRT_TYPE(jchar, Char) + CALL_NONVIRT_TYPE(jshort, Short) + CALL_NONVIRT_TYPE(jint, Int) + CALL_NONVIRT_TYPE(jlong, Long) + CALL_NONVIRT_TYPE(jfloat, Float) + CALL_NONVIRT_TYPE(jdouble, Double) + + void CallNonvirtualVoidMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) + { + va_list args; + va_start(args, methodID); + functions->CallNonvirtualVoidMethodV(this, obj, clazz, methodID, args); + va_end(args); + } + void CallNonvirtualVoidMethodV(jobject obj, jclass clazz, + jmethodID methodID, va_list args) + { + functions->CallNonvirtualVoidMethodV(this, obj, clazz, methodID, args); + } + void CallNonvirtualVoidMethodA(jobject obj, jclass clazz, + jmethodID methodID, const jvalue *args) + { + functions->CallNonvirtualVoidMethodA(this, obj, clazz, methodID, args); + } + + jfieldID GetFieldID(jclass clazz, const char *name, const char *sig) + { + return functions->GetFieldID(this, clazz, name, sig); + } + + jobject GetObjectField(jobject obj, jfieldID fieldID) + { + return functions->GetObjectField(this, obj, fieldID); + } + jboolean GetBooleanField(jobject obj, jfieldID fieldID) + { + return functions->GetBooleanField(this, obj, fieldID); + } + jbyte GetByteField(jobject obj, jfieldID fieldID) + { + return functions->GetByteField(this, obj, fieldID); + } + jchar GetCharField(jobject obj, jfieldID fieldID) + { + return functions->GetCharField(this, obj, fieldID); + } + jshort GetShortField(jobject obj, jfieldID fieldID) + { + return functions->GetShortField(this, obj, fieldID); + } + jint GetIntField(jobject obj, jfieldID fieldID) + { + return functions->GetIntField(this, obj, fieldID); + } + jlong GetLongField(jobject obj, jfieldID fieldID) + { + return functions->GetLongField(this, obj, fieldID); + } + jfloat GetFloatField(jobject obj, jfieldID fieldID) + { + return functions->GetFloatField(this, obj, fieldID); + } + jdouble GetDoubleField(jobject obj, jfieldID fieldID) + { + return functions->GetDoubleField(this, obj, fieldID); + } + + void SetObjectField(jobject obj, jfieldID fieldID, jobject val) + { + functions->SetObjectField(this, obj, fieldID, val); + } + void SetBooleanField(jobject obj, jfieldID fieldID, jboolean val) + { + functions->SetBooleanField(this, obj, fieldID, val); + } + void SetByteField(jobject obj, jfieldID fieldID, jbyte val) + { + functions->SetByteField(this, obj, fieldID, val); + } + void SetCharField(jobject obj, jfieldID fieldID, jchar val) + { + functions->SetCharField(this, obj, fieldID, val); + } + void SetShortField(jobject obj, jfieldID fieldID, jshort val) + { + functions->SetShortField(this, obj, fieldID, val); + } + void SetIntField(jobject obj, jfieldID fieldID, jint val) + { + functions->SetIntField(this, obj, fieldID, val); + } + void SetLongField(jobject obj, jfieldID fieldID, jlong val) + { + functions->SetLongField(this, obj, fieldID, val); + } + void SetFloatField(jobject obj, jfieldID fieldID, jfloat val) + { + functions->SetFloatField(this, obj, fieldID, val); + } + void SetDoubleField(jobject obj, jfieldID fieldID, jdouble val) + { + functions->SetDoubleField(this, obj, fieldID, val); + } + + jmethodID GetStaticMethodID(jclass clazz, const char *name, const char *sig) + { + return functions->GetStaticMethodID(this, clazz, name, sig); + } + +#define CALL_STATIC_TYPE_METHOD(_jtype, _jname) \ + _jtype CallStatic##_jname##Method(jclass clazz, jmethodID methodID, \ + ...) \ + { \ + _jtype result; \ + va_list args; \ + va_start(args, methodID); \ + result = functions->CallStatic##_jname##MethodV(this, clazz, \ + methodID, args); \ + va_end(args); \ + return result; \ + } +#define CALL_STATIC_TYPE_METHODV(_jtype, _jname) \ + _jtype CallStatic##_jname##MethodV(jclass clazz, jmethodID methodID, \ + va_list args) \ + { \ + return functions->CallStatic##_jname##MethodV(this, clazz, methodID, \ + args); \ + } +#define CALL_STATIC_TYPE_METHODA(_jtype, _jname) \ + _jtype CallStatic##_jname##MethodA(jclass clazz, jmethodID methodID, \ + const jvalue *args) \ + { \ + return functions->CallStatic##_jname##MethodA(this, clazz, methodID, \ + args); \ + } + +#define CALL_STATIC_TYPE(_jtype, _jname) \ + CALL_STATIC_TYPE_METHOD(_jtype, _jname) \ + CALL_STATIC_TYPE_METHODV(_jtype, _jname) \ + CALL_STATIC_TYPE_METHODA(_jtype, _jname) + + CALL_STATIC_TYPE(jobject, Object) + CALL_STATIC_TYPE(jboolean, Boolean) + CALL_STATIC_TYPE(jbyte, Byte) + CALL_STATIC_TYPE(jchar, Char) + CALL_STATIC_TYPE(jshort, Short) + CALL_STATIC_TYPE(jint, Int) + CALL_STATIC_TYPE(jlong, Long) + CALL_STATIC_TYPE(jfloat, Float) + CALL_STATIC_TYPE(jdouble, Double) + + void CallStaticVoidMethod(jclass clazz, jmethodID methodID, ...) + { + va_list args; + va_start(args, methodID); + functions->CallStaticVoidMethodV(this, clazz, methodID, args); + va_end(args); + } + void CallStaticVoidMethodV(jclass clazz, jmethodID methodID, va_list args) + { + functions->CallStaticVoidMethodV(this, clazz, methodID, args); + } + void CallStaticVoidMethodA(jclass clazz, jmethodID methodID, const jvalue *args) + { + functions->CallStaticVoidMethodA(this, clazz, methodID, args); + } + + jfieldID GetStaticFieldID(jclass clazz, const char *name, const char *sig) + { + return functions->GetStaticFieldID(this, clazz, name, sig); + } + + jobject GetStaticObjectField(jclass clazz, jfieldID fieldID) + { + return functions->GetStaticObjectField(this, clazz, fieldID); + } + jboolean GetStaticBooleanField(jclass clazz, jfieldID fieldID) + { + return functions->GetStaticBooleanField(this, clazz, fieldID); + } + jbyte GetStaticByteField(jclass clazz, jfieldID fieldID) + { + return functions->GetStaticByteField(this, clazz, fieldID); + } + jchar GetStaticCharField(jclass clazz, jfieldID fieldID) + { + return functions->GetStaticCharField(this, clazz, fieldID); + } + jshort GetStaticShortField(jclass clazz, jfieldID fieldID) + { + return functions->GetStaticShortField(this, clazz, fieldID); + } + jint GetStaticIntField(jclass clazz, jfieldID fieldID) + { + return functions->GetStaticIntField(this, clazz, fieldID); + } + jlong GetStaticLongField(jclass clazz, jfieldID fieldID) + { + return functions->GetStaticLongField(this, clazz, fieldID); + } + jfloat GetStaticFloatField(jclass clazz, jfieldID fieldID) + { + return functions->GetStaticFloatField(this, clazz, fieldID); + } + jdouble GetStaticDoubleField(jclass clazz, jfieldID fieldID) + { + return functions->GetStaticDoubleField(this, clazz, fieldID); + } + + void SetStaticObjectField(jclass clazz, jfieldID fieldID, jobject val) + { + functions->SetStaticObjectField(this, clazz, fieldID, val); + } + void SetStaticBooleanField(jclass clazz, jfieldID fieldID, jboolean val) + { + functions->SetStaticBooleanField(this, clazz, fieldID, val); + } + void SetStaticByteField(jclass clazz, jfieldID fieldID, jbyte val) + { + functions->SetStaticByteField(this, clazz, fieldID, val); + } + void SetStaticCharField(jclass clazz, jfieldID fieldID, jchar val) + { + functions->SetStaticCharField(this, clazz, fieldID, val); + } + void SetStaticShortField(jclass clazz, jfieldID fieldID, jshort val) + { + functions->SetStaticShortField(this, clazz, fieldID, val); + } + void SetStaticIntField(jclass clazz, jfieldID fieldID, jint val) + { + functions->SetStaticIntField(this, clazz, fieldID, val); + } + void SetStaticLongField(jclass clazz, jfieldID fieldID, jlong val) + { + functions->SetStaticLongField(this, clazz, fieldID, val); + } + void SetStaticFloatField(jclass clazz, jfieldID fieldID, jfloat val) + { + functions->SetStaticFloatField(this, clazz, fieldID, val); + } + void SetStaticDoubleField(jclass clazz, jfieldID fieldID, jdouble val) + { + functions->SetStaticDoubleField(this, clazz, fieldID, val); + } + + jstring NewString(const jchar *unicodeChars, jsize len) + { + return functions->NewString(this, unicodeChars, len); + } + + jsize GetStringLength(jstring string) + { + return functions->GetStringLength(this, string); + } + + const jchar *GetStringChars(jstring string, jboolean *isCopy) + { + return functions->GetStringChars(this, string, isCopy); + } + + void ReleaseStringChars(jstring string, const jchar *chars) + { + functions->ReleaseStringChars(this, string, chars); + } + + jstring NewStringUTF(const char *bytes) + { + return functions->NewStringUTF(this, bytes); + } + + jsize GetStringUTFLength(jstring string) + { + return functions->GetStringUTFLength(this, string); + } + + const char *GetStringUTFChars(jstring string, jboolean *isCopy) + { + return functions->GetStringUTFChars(this, string, isCopy); + } + + void ReleaseStringUTFChars(jstring string, const char *utf) + { + functions->ReleaseStringUTFChars(this, string, utf); + } + + jsize GetArrayLength(jarray array) + { + return functions->GetArrayLength(this, array); + } + + jobjectArray NewObjectArray(jsize length, jclass elementClass, + jobject initialElement) + { + return functions->NewObjectArray(this, length, elementClass, + initialElement); + } + + jobject GetObjectArrayElement(jobjectArray array, jsize index) + { + return functions->GetObjectArrayElement(this, array, index); + } + + void SetObjectArrayElement(jobjectArray array, jsize index, jobject val) + { + functions->SetObjectArrayElement(this, array, index, val); + } + + jbooleanArray NewBooleanArray(jsize length) + { + return functions->NewBooleanArray(this, length); + } + jbyteArray NewByteArray(jsize length) + { + return functions->NewByteArray(this, length); + } + jcharArray NewCharArray(jsize length) + { + return functions->NewCharArray(this, length); + } + jshortArray NewShortArray(jsize length) + { + return functions->NewShortArray(this, length); + } + jintArray NewIntArray(jsize length) + { + return functions->NewIntArray(this, length); + } + jlongArray NewLongArray(jsize length) + { + return functions->NewLongArray(this, length); + } + jfloatArray NewFloatArray(jsize length) + { + return functions->NewFloatArray(this, length); + } + jdoubleArray NewDoubleArray(jsize length) + { + return functions->NewDoubleArray(this, length); + } + + jboolean *GetBooleanArrayElements(jbooleanArray array, jboolean *isCopy) + { + return functions->GetBooleanArrayElements(this, array, isCopy); + } + jbyte *GetByteArrayElements(jbyteArray array, jboolean *isCopy) + { + return functions->GetByteArrayElements(this, array, isCopy); + } + jchar *GetCharArrayElements(jcharArray array, jboolean *isCopy) + { + return functions->GetCharArrayElements(this, array, isCopy); + } + jshort *GetShortArrayElements(jshortArray array, jboolean *isCopy) + { + return functions->GetShortArrayElements(this, array, isCopy); + } + jint *GetIntArrayElements(jintArray array, jboolean *isCopy) + { + return functions->GetIntArrayElements(this, array, isCopy); + } + jlong *GetLongArrayElements(jlongArray array, jboolean *isCopy) + { + return functions->GetLongArrayElements(this, array, isCopy); + } + jfloat *GetFloatArrayElements(jfloatArray array, jboolean *isCopy) + { + return functions->GetFloatArrayElements(this, array, isCopy); + } + jdouble *GetDoubleArrayElements(jdoubleArray array, jboolean *isCopy) + { + return functions->GetDoubleArrayElements(this, array, isCopy); + } + + void ReleaseBooleanArrayElements(jbooleanArray array, jboolean *elems, + jint mode) + { + functions->ReleaseBooleanArrayElements(this, array, elems, mode); + } + void ReleaseByteArrayElements(jbyteArray array, jbyte *elems, + jint mode) + { + functions->ReleaseByteArrayElements(this, array, elems, mode); + } + void ReleaseCharArrayElements(jcharArray array, jchar *elems, + jint mode) + { + functions->ReleaseCharArrayElements(this, array, elems, mode); + } + void ReleaseShortArrayElements(jshortArray array, jshort *elems, + jint mode) + { + functions->ReleaseShortArrayElements(this, array, elems, mode); + } + void ReleaseIntArrayElements(jintArray array, jint *elems, + jint mode) + { + functions->ReleaseIntArrayElements(this, array, elems, mode); + } + void ReleaseLongArrayElements(jlongArray array, jlong *elems, + jint mode) + { + functions->ReleaseLongArrayElements(this, array, elems, mode); + } + void ReleaseFloatArrayElements(jfloatArray array, jfloat *elems, + jint mode) + { + functions->ReleaseFloatArrayElements(this, array, elems, mode); + } + void ReleaseDoubleArrayElements(jdoubleArray array, jdouble *elems, + jint mode) + { + functions->ReleaseDoubleArrayElements(this, array, elems, mode); + } + + void GetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len, + jboolean *buf) + { + functions->GetBooleanArrayRegion(this, array, start, len, buf); + } + void GetByteArrayRegion(jbyteArray array, jsize start, jsize len, + jbyte *buf) + { + functions->GetByteArrayRegion(this, array, start, len, buf); + } + void GetCharArrayRegion(jcharArray array, jsize start, jsize len, + jchar *buf) + { + functions->GetCharArrayRegion(this, array, start, len, buf); + } + void GetShortArrayRegion(jshortArray array, jsize start, jsize len, + jshort *buf) + { + functions->GetShortArrayRegion(this, array, start, len, buf); + } + void GetIntArrayRegion(jintArray array, jsize start, jsize len, + jint *buf) + { + functions->GetIntArrayRegion(this, array, start, len, buf); + } + void GetLongArrayRegion(jlongArray array, jsize start, jsize len, + jlong *buf) + { + functions->GetLongArrayRegion(this, array, start, len, buf); + } + void GetFloatArrayRegion(jfloatArray array, jsize start, jsize len, + jfloat *buf) + { + functions->GetFloatArrayRegion(this, array, start, len, buf); + } + void GetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len, + jdouble *buf) + { + functions->GetDoubleArrayRegion(this, array, start, len, buf); + } + + void SetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len, + const jboolean *buf) + { + functions->SetBooleanArrayRegion(this, array, start, len, buf); + } + void SetByteArrayRegion(jbyteArray array, jsize start, jsize len, + const jbyte *buf) + { + functions->SetByteArrayRegion(this, array, start, len, buf); + } + void SetCharArrayRegion(jcharArray array, jsize start, jsize len, + const jchar *buf) + { + functions->SetCharArrayRegion(this, array, start, len, buf); + } + void SetShortArrayRegion(jshortArray array, jsize start, jsize len, + const jshort *buf) + { + functions->SetShortArrayRegion(this, array, start, len, buf); + } + void SetIntArrayRegion(jintArray array, jsize start, jsize len, + const jint *buf) + { + functions->SetIntArrayRegion(this, array, start, len, buf); + } + void SetLongArrayRegion(jlongArray array, jsize start, jsize len, + const jlong *buf) + { + functions->SetLongArrayRegion(this, array, start, len, buf); + } + void SetFloatArrayRegion(jfloatArray array, jsize start, jsize len, + const jfloat *buf) + { + functions->SetFloatArrayRegion(this, array, start, len, buf); + } + void SetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len, + const jdouble *buf) + { + functions->SetDoubleArrayRegion(this, array, start, len, buf); + } + + jint RegisterNatives(jclass clazz, const JNINativeMethod *methods, + jint nMethods) + { + return functions->RegisterNatives(this, clazz, methods, nMethods); + } + + jint UnregisterNatives(jclass clazz) + { + return functions->UnregisterNatives(this, clazz); + } + + jint MonitorEnter(jobject obj) + { + return functions->MonitorEnter(this, obj); + } + + jint MonitorExit(jobject obj) + { + return functions->MonitorExit(this, obj); + } + + jint GetJavaVM(JavaVM **vm) + { + return functions->GetJavaVM(this, vm); + } + + void GetStringRegion(jstring str, jsize start, jsize len, jchar *buf) + { + functions->GetStringRegion(this, str, start, len, buf); + } + + void GetStringUTFRegion(jstring str, jsize start, jsize len, char *buf) + { + return functions->GetStringUTFRegion(this, str, start, len, buf); + } + + void *GetPrimitiveArrayCritical(jarray array, jboolean *isCopy) + { + return functions->GetPrimitiveArrayCritical(this, array, isCopy); + } + + void ReleasePrimitiveArrayCritical(jarray array, void *carray, jint mode) + { + functions->ReleasePrimitiveArrayCritical(this, array, carray, mode); + } + + const jchar *GetStringCritical(jstring string, jboolean *isCopy) + { + return functions->GetStringCritical(this, string, isCopy); + } + + void ReleaseStringCritical(jstring string, const jchar *carray) + { + functions->ReleaseStringCritical(this, string, carray); + } + + jweak NewWeakGlobalRef(jobject obj) + { + return functions->NewWeakGlobalRef(this, obj); + } + + void DeleteWeakGlobalRef(jweak obj) + { + functions->DeleteWeakGlobalRef(this, obj); + } + + jboolean ExceptionCheck() + { + return functions->ExceptionCheck(this); + } + + jobject NewDirectByteBuffer(void *address, jlong capacity) + { + return functions->NewDirectByteBuffer(this, address, capacity); + } + + void *GetDirectBufferAddress(jobject buf) + { + return functions->GetDirectBufferAddress(this, buf); + } + + jlong GetDirectBufferCapacity(jobject buf) + { + return functions->GetDirectBufferCapacity(this, buf); + } + + /* added in JNI 1.6 */ + jobjectRefType GetObjectRefType(jobject obj) + { + return functions->GetObjectRefType(this, obj); + } +#endif /*__cplusplus*/ +}; + +/* + * JNI invocation interface. + */ +struct JNIInvokeInterface +{ + void *reserved0; + void *reserved1; + void *reserved2; + + jint (*DestroyJavaVM)(JavaVM *vm); + jint (*AttachCurrentThread)(JavaVM *vm, JNIEnv **p_env, void *thr_args); + jint (*DetachCurrentThread)(JavaVM *vm); + jint (*GetEnv)(JavaVM *vm, void **p_env, jint version); + jint (*AttachCurrentThreadAsDaemon)(JavaVM *vm, JNIEnv **p_env, void *thr_args); +}; + +/* + * C++ version. + */ +struct _JavaVM +{ + const struct JNIInvokeInterface *functions; + +#if defined(__cplusplus) + jint DestroyJavaVM() + { + return functions->DestroyJavaVM(this); + } + jint AttachCurrentThread(JNIEnv **p_env, void *thr_args) + { + return functions->AttachCurrentThread(this, p_env, thr_args); + } + jint DetachCurrentThread() + { + return functions->DetachCurrentThread(this); + } + jint GetEnv(void **env, jint version) + { + return functions->GetEnv(this, env, version); + } + jint AttachCurrentThreadAsDaemon(JNIEnv **p_env, void *thr_args) + { + return functions->AttachCurrentThreadAsDaemon(this, p_env, thr_args); + } +#endif /*__cplusplus*/ +}; + +struct JavaVMAttachArgs +{ + jint version; /* must be >= JNI_VERSION_1_2 */ + const char *name; /* NULL or name of thread as modified UTF-8 str */ + jobject group; /* global ref of a ThreadGroup object, or NULL */ +}; +typedef struct JavaVMAttachArgs JavaVMAttachArgs; + +/* + * JNI 1.2+ initialization. (As of 1.6, the pre-1.2 structures are no + * longer supported.) + */ +typedef struct JavaVMOption +{ + const char *optionString; + void *extraInfo; +} JavaVMOption; + +typedef struct JavaVMInitArgs +{ + jint version; /* use JNI_VERSION_1_2 or later */ + + jint nOptions; + JavaVMOption *options; + jboolean ignoreUnrecognized; +} JavaVMInitArgs; + +#ifdef __cplusplus +extern "C" +{ +#endif + /* + * VM initialization functions. + * + * Note these are the only symbols exported for JNI by the VM. + */ + + jint JNI_GetDefaultJavaVMInitArgs(void *); + jint JNI_CreateJavaVM(JavaVM **, JNIEnv **, void *); + jint JNI_GetCreatedJavaVMs(JavaVM **, jsize, jsize *); + +#define JNIIMPORT +#define JNIEXPORT __attribute__((visibility("default"))) +#define JNICALL + + /* + * Prototypes for functions exported by loadable shared libs. These are + * called by JNI, not provided by JNI. + */ + JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved); + JNIEXPORT void JNI_OnUnload(JavaVM *vm, void *reserved); + +#ifdef __cplusplus +} +#endif + +/* + * Manifest constants. + */ +#define JNI_FALSE 0 +#define JNI_TRUE 1 + +#define JNI_VERSION_1_1 0x00010001 +#define JNI_VERSION_1_2 0x00010002 +#define JNI_VERSION_1_4 0x00010004 +#define JNI_VERSION_1_6 0x00010006 + +#define JNI_OK (0) /* no error */ +#define JNI_ERR (-1) /* generic error */ +#define JNI_EDETACHED (-2) /* thread detached from the VM */ +#define JNI_EVERSION (-3) /* JNI version error */ +#define JNI_ENOMEM (-4) /* Out of memory */ +#define JNI_EEXIST (-5) /* VM already created */ +#define JNI_EINVAL (-6) /* Invalid argument */ + +#define JNI_COMMIT 1 /* copy content, do not free buffer */ +#define JNI_ABORT 2 /* free buffer w/o copying back */ diff --git a/pkgs/jni/tool/generate_ffi_bindings.dart b/pkgs/jni/tool/generate_ffi_bindings.dart new file mode 100644 index 000000000..35b9db2b3 --- /dev/null +++ b/pkgs/jni/tool/generate_ffi_bindings.dart @@ -0,0 +1,68 @@ +// 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. + +// This script generates all FFIGEN-based bindings we require to use JNI, which +// includes some C wrappers over `JNIEnv` type and some Dart extension methods. + +import 'dart:io'; + +import 'package:logging/logging.dart'; +import 'package:args/args.dart'; + +import 'wrapper_generators/logging.dart'; +import 'wrapper_generators/generate_c_extensions.dart'; +import 'wrapper_generators/generate_dart_extensions.dart'; + +import 'package:ffigen/ffigen.dart' as ffigen; + +void main(List args) { + final levels = Map.fromEntries( + Level.LEVELS.map((l) => MapEntry(l.name.toLowerCase(), l)), + ); + final argParser = ArgParser() + ..addOption( + 'verbose', + defaultsTo: 'severe', + help: 'set ffigen log verbosity', + allowed: levels.keys, + ) + ..addFlag( + 'help', + negatable: false, + abbr: 'h', + defaultsTo: false, + help: 'display this help message', + ); + + final argResults = argParser.parse(args); + + if (argResults['help']) { + stderr.writeln('Generates FFI bindings required for package:jni'); + stderr.writeln(argParser.usage); + exitCode = 1; + return; + } + + hierarchicalLoggingEnabled = true; + Logger.root.level = levels[argResults['verbose']]!; + logger.level = Level.INFO; + Logger.root.onRecord.listen((record) { + stderr.writeln('${record.level.name}: ${record.message}'); + }); + + logger.info("Generating C wrappers"); + final minimalConfig = ffigen.Config.fromFile(File('ffigen_exts.yaml')); + final minimalLibrary = ffigen.parse(minimalConfig); + generateCWrappers(minimalLibrary); + + logger.info("Generating FFI bindings for package:jni"); + + final config = ffigen.Config.fromFile(File('ffigen.yaml')); + final library = ffigen.parse(config); + final outputFile = File(config.output); + library.generateFile(outputFile); + + logger.info("Generating Dart extensions"); + generateDartExtensions(library); +} diff --git a/pkgs/jni/tool/generate_ide_files.dart b/pkgs/jni/tool/generate_ide_files.dart new file mode 100644 index 000000000..ab44ad8d2 --- /dev/null +++ b/pkgs/jni/tool/generate_ide_files.dart @@ -0,0 +1,65 @@ +// 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. + +import 'dart:io'; + +import 'package:args/args.dart'; + +const makefilesGenerator = 'make'; +const ninjaGenerator = 'ninja'; + +const cmakeGeneratorNames = { + makefilesGenerator: 'Unix Makefiles', + ninjaGenerator: 'Ninja', +}; + +void runCommand(String exec, List args, String workingDirectory) { + stderr.writeln('+ $exec ${args.join(" ")}'); + final process = + Process.runSync(exec, args, workingDirectory: workingDirectory); + if (process.exitCode != 0) { + stdout.writeln(process.stdout); + stderr.writeln(process.stderr); + throw "command failed with exit code ${process.exitCode}"; + } +} + +void main(List arguments) { + final argParser = ArgParser() + ..addOption( + "generator", + abbr: 'G', + help: 'Generator to pass to CMake. (Either "ninja" or "make").', + allowed: [ninjaGenerator, makefilesGenerator], + defaultsTo: Platform.isWindows ? ninjaGenerator : makefilesGenerator, + ) + ..addFlag('help', abbr: 'h', help: 'Show this usage information.'); + final argResults = argParser.parse(arguments); + if (argResults.rest.isNotEmpty || argResults['help']) { + stderr.writeln('This script generates compile_commands.json for ' + 'C source files in src/'); + stderr.writeln(argParser.usage); + exitCode = 1; + return; + } + final generator = cmakeGeneratorNames[argResults['generator']]; + final tempDir = Directory.current.createTempSync("clangd_setup_temp_"); + final src = Directory.current.uri.resolve("src/"); + try { + runCommand( + "cmake", + [ + "-DCMAKE_EXPORT_COMPILE_COMMANDS=1", + src.toFilePath(), + "-G", + generator!, + ], + tempDir.path); + final createdFile = tempDir.uri.resolve("compile_commands.json"); + final target = src.resolve("compile_commands.json"); + File.fromUri(createdFile).renameSync(target.toFilePath()); + } finally { + tempDir.deleteSync(recursive: true); + } +} diff --git a/pkgs/jni/tool/wrapper_generators/ffigen_util.dart b/pkgs/jni/tool/wrapper_generators/ffigen_util.dart new file mode 100644 index 000000000..2b234f6a9 --- /dev/null +++ b/pkgs/jni/tool/wrapper_generators/ffigen_util.dart @@ -0,0 +1,50 @@ +// Copyright (c) 2023, 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. + +import 'package:ffigen/src/code_generator/writer.dart'; +import 'package:ffigen/src/code_generator.dart'; + +final dummyWriter = Writer( + lookUpBindings: [], + ffiNativeBindings: [], + noLookUpBindings: [], + className: 'unused', +); + +/// Find compound having [name] in [library]. +Compound findCompound(library, String name) { + return library.bindings.firstWhere((element) => element.name == name) + as Compound; +} + +const preamble = ''' +// Auto generated file. Do not edit. + +// This is generated from JNI header in Android NDK. License for the same is +// provided below. + +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * JNI specification, as defined by Sun: + * http://java.sun.com/javase/6/docs/technotes/guides/jni/spec/jniTOC.html + * + * Everything here is expected to be VM-neutral. + */ + +'''; diff --git a/pkgs/jni/tool/wrapper_generators/generate_c_extensions.dart b/pkgs/jni/tool/wrapper_generators/generate_c_extensions.dart new file mode 100644 index 000000000..f1e15b21e --- /dev/null +++ b/pkgs/jni/tool/wrapper_generators/generate_c_extensions.dart @@ -0,0 +1,297 @@ +// Copyright (c) 2023, 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. + +import 'dart:io'; + +import 'package:ffigen/src/code_generator.dart'; + +import 'ffigen_util.dart'; +import 'logging.dart'; + +class Paths { + static final currentDir = Directory.current.uri; + static final src = currentDir.resolve("src/"); + static final thirdParty = src.resolve("third_party/"); + static final globalJniEnvH = thirdParty.resolve("global_jni_env.h"); + static final globalJniEnvC = thirdParty.resolve("global_jni_env.c"); + static final bindingsDir = currentDir.resolve("lib/src/third_party/"); + static final envExtensions = bindingsDir.resolve("env_extensions.dart"); +} + +/// Name of variable used in wrappers to hold the result. +const resultVar = '_result'; + +/// Name of variable used in wrappers to hold the exception. +const errorVar = '_exception'; + +/// Name of JNIEnv struct definition in JNI headers. +const envType = 'JNINativeInterface'; + +/// Name of wrapper to JNIEnv +const wrapperName = 'GlobalJniEnvStruct'; + +const wrapperIncludes = ''' +#include "global_jni_env.h" + +'''; + +const wrapperDeclIncludes = ''' +#include +#include "../dartjni.h" + +'''; + +const wrapperGetter = ''' +FFI_PLUGIN_EXPORT +$wrapperName* GetGlobalEnv() { + if (jni->jvm == NULL) { + return NULL; + } + return &globalJniEnv; +} +'''; + +const wrapperGetterDecl = ''' +FFI_PLUGIN_EXPORT $wrapperName* GetGlobalEnv(); +'''; + +/// Get C name of a type from its ffigen representation. +String getCType(Type type) { + if (type is PointerType) { + return '${getCType(type.child)}*'; + } + final cType = type.getCType(dummyWriter); + const specialCaseMappings = { + 'JNIEnv1': 'JNIEnv', + 'ffi.Char': 'char', + 'ffi.Void': 'void', + 'ffi.Int': 'int', + 'ffi.Int32': 'int32_t', + }; + return specialCaseMappings[cType] ?? cType; +} + +/// Get type of wrapping function for a JNIEnv function. +FunctionType getGlobalJniEnvFunctionType(FunctionType ft) { + return FunctionType( + returnType: ft.returnType, + parameters: ft.parameters.sublist(1), + ); +} + +// Returns declaration of function field in GlobalJniEnv struct +String getFunctionFieldDecl( + Member field, +) { + final fieldType = field.type; + if (fieldType is PointerType && fieldType.child is NativeFunc) { + final nativeFunc = fieldType.child as NativeFunc; + final functionType = getGlobalJniEnvFunctionType(nativeFunc.type); + final resultWrapper = getResultWrapper(getCType(functionType.returnType)); + final name = field.name; + final params = functionType.parameters + .map((param) => '${getCType(param.type)} ${param.name}') + .join(', '); + return ('${resultWrapper.returnType} (*$name)($params);'); + } else { + return 'void* ${field.name};'; + } +} + +String getWrapperFuncName(Member field) { + return 'globalEnv_${field.name}'; +} + +class ResultWrapper { + String returnType, onResult, onError; + ResultWrapper.withResultAndError( + this.returnType, this.onResult, this.onError); + ResultWrapper.unionType( + String returnType, + String defaultValue, + ) : this.withResultAndError( + returnType, + '($returnType){.value = $resultVar, .exception = NULL}', + '($returnType){.value = $defaultValue, .exception = $errorVar}', + ); + ResultWrapper.forJValueField(String fieldChar) + : this.withResultAndError( + 'JniResult', + '(JniResult){.value = {.$fieldChar = $resultVar}, .exception = NULL}', + '(JniResult){.value = {.j = 0}, .exception = $errorVar}', + ); +} + +ResultWrapper getResultWrapper(String returnType) { + if (returnType.endsWith("*")) { + return ResultWrapper.unionType('JniPointerResult', 'NULL'); + } + + final jobjectWrapper = ResultWrapper.forJValueField('l'); + if (returnType.endsWith('Array')) { + return jobjectWrapper; + } + + const jfields = { + 'jboolean': 'z', + 'jbyte': 'b', + 'jshort': 's', + 'jchar': 'c', + 'jint': 'i', + 'jsize': 'i', // jsize is an alias to jint + 'jfloat': 'f', + 'jlong': 'j', + 'jdouble': 'd', + 'jobject': 'l', + 'jweak': 'l', + 'jarray': 'l', + 'jstring': 'l', + 'jthrowable': 'l', + }; + + switch (returnType) { + case 'void': + return ResultWrapper.withResultAndError( + 'jthrowable', + 'NULL', + errorVar, + ); + case 'jmethodID': + case 'jfieldID': + return ResultWrapper.unionType('JniPointerResult', 'NULL'); + case 'jclass': + return ResultWrapper.unionType('JniClassLookupResult', 'NULL'); + case 'int32_t': + return ResultWrapper.forJValueField('i'); + default: + if (jfields.containsKey(returnType)) { + return ResultWrapper.forJValueField(jfields[returnType]!); + } + throw 'Unknown type $returnType for return type'; + } +} + +bool isJRefType(String type) { + // No need to include jweak here, its only returned by ref-related functions. + const refTypes = { + 'jclass', + 'jobject', + 'jstring', + 'jthrowable', + 'jarray', + 'jweak' + }; + return (type.startsWith('j') && type.endsWith('Array')) || + refTypes.contains(type); +} + +const refFunctions = { + 'NewGlobalRef', + 'DeleteGlobalRef', + 'NewLocalRef', + 'DeleteLocalRef', + 'NewWeakGlobalRef', + 'DeleteWeakGlobalRef', +}; + +/// These return const ptrs so the assignment statement needs to be +/// adjusted in the wrapper. +const constBufferReturningFunctions = { + 'GetStringChars', + 'GetStringUTFChars', + 'GetStringCritical', +}; + +/// Methods which do not throw exceptions, and thus not need to be checked +const _noCheckException = { + 'GetVersion', + 'GetStringCritical', + 'ExceptionClear', + 'ExceptionDescribe', +}; + +String? getWrapperFunc(Member field) { + final fieldType = field.type; + if (fieldType is PointerType && fieldType.child is NativeFunc) { + final functionType = (fieldType.child as NativeFunc).type; + if (functionType.parameters.first.name.isEmpty) { + return null; + } + + final outerFunctionType = getGlobalJniEnvFunctionType(functionType); + final wrapperName = getWrapperFuncName(field); + final returnType = getCType(outerFunctionType.returnType); + final params = outerFunctionType.parameters + .map((param) => '${getCType(param.type)} ${param.name}') + .join(', '); + var returnCapture = returnType == 'void' ? '' : '$returnType $resultVar ='; + if (constBufferReturningFunctions.contains(field.name)) { + returnCapture = 'const $returnCapture'; + } + final callParams = [ + 'jniEnv', + ...(outerFunctionType.parameters.map((param) => param.name).toList()) + ].join(', '); + final resultWrapper = getResultWrapper(returnType); + + var convertRef = ''; + if (isJRefType(returnType) && !refFunctions.contains(field.name)) { + convertRef = ' $resultVar = to_global_ref($resultVar);\n'; + } + final exceptionCheck = _noCheckException.contains(field.name) + ? '' + : ' jthrowable $errorVar = check_exception();\n' + ' if ($errorVar != NULL) {\n' + ' return ${resultWrapper.onError};\n' + ' }\n'; + return '${resultWrapper.returnType} $wrapperName($params) {\n' + ' attach_thread();\n' + ' $returnCapture (*jniEnv)->${field.name}($callParams);\n' + '$exceptionCheck' + '$convertRef' + ' return ${resultWrapper.onResult};\n' + '}\n'; + } + return null; +} + +void writeGlobalJniEnvWrapper(Library library) { + final jniEnvType = findCompound(library, envType); + + final fieldDecls = jniEnvType.members.map(getFunctionFieldDecl).join('\n'); + final structDecl = + 'typedef struct $wrapperName {\n$fieldDecls\n} $wrapperName;\n'; + File.fromUri(Paths.globalJniEnvH).writeAsStringSync( + '$preamble$wrapperDeclIncludes$structDecl$wrapperGetterDecl'); + + final functionWrappers = StringBuffer(); + final structInst = StringBuffer('$wrapperName globalJniEnv = {\n'); + for (final member in jniEnvType.members) { + final wrapper = getWrapperFunc(member); + if (wrapper == null) { + structInst.write('.${member.name} = NULL,\n'); + } else { + structInst.write('.${member.name} = ${getWrapperFuncName(member)},\n'); + functionWrappers.write('$wrapper\n'); + } + } + structInst.write('};'); + File.fromUri(Paths.globalJniEnvC).writeAsStringSync( + '$preamble$wrapperIncludes$functionWrappers$structInst$wrapperGetter'); +} + +void executeClangFormat(List files) { + final paths = files.map((u) => u.toFilePath()).toList(); + logger.info('execute clang-format -i ${paths.join(" ")}'); + final format = Process.runSync('clang-format', ['-i', ...paths]); + if (format.exitCode != 0) { + stderr.writeln('clang-format exited with ${format.exitCode}'); + stderr.writeln(format.stderr); + } +} + +void generateCWrappers(Library minimalLibrary) { + writeGlobalJniEnvWrapper(minimalLibrary); + executeClangFormat([Paths.globalJniEnvC, Paths.globalJniEnvH]); +} diff --git a/pkgs/jni/tool/wrapper_generators/generate_dart_extensions.dart b/pkgs/jni/tool/wrapper_generators/generate_dart_extensions.dart new file mode 100644 index 000000000..c78b88368 --- /dev/null +++ b/pkgs/jni/tool/wrapper_generators/generate_dart_extensions.dart @@ -0,0 +1,253 @@ +// Copyright (c) 2023, 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. + +import 'dart:io'; + +import 'package:collection/collection.dart'; +import 'package:ffigen/src/code_generator.dart'; + +import 'ffigen_util.dart'; +import 'logging.dart'; + +class Paths { + static final currentDir = Directory.current.uri; + static final bindingsDir = currentDir.resolve("lib/src/third_party/"); + // Contains extensions for our C wrapper types. + static final globalEnvExts = + bindingsDir.resolve("global_env_extensions.dart"); + // Contains extensions for JNI's struct types. + static final localEnvExts = + bindingsDir.resolve("jnienv_javavm_extensions.dart"); +} + +const writeLocalEnvExtensions = false; + +void executeDartFormat(List files) { + final paths = files.map((u) => u.toFilePath()).toList(); + logger.info('execute dart format ${paths.join(" ")}'); + final format = Process.runSync('dart', ['format', ...paths]); + if (format.exitCode != 0) { + logger.severe('dart format exited with ${format.exitCode}'); + stderr.writeln(format.stderr); + } +} + +const globalEnvType = 'GlobalJniEnvStruct'; +const localEnvType = 'JNINativeInterface'; +const jvmType = 'JNIInvokeInterface'; + +String getCheckedGetter(Type returnType) { + if (returnType is PointerType) { + final child = returnType.child.getCType(dummyWriter); + return 'getPointer<$child>()'; + } + final cType = returnType.getCType(dummyWriter); + if (cType.endsWith("ArrayPtr")) { + return 'object'; + } + const mappings = { + 'JBooleanMarker': 'boolean', + 'JByteMarker': 'byte', + 'JShortMarker': 'short', + 'JCharMarker': 'char', + 'JIntMarker': 'integer', + 'JSizeMarker': 'integer', // jsize is aliased to jint + 'JLongMarker': 'long', + 'JFloatMarker': 'float', + 'JDoubleMarker': 'doubleFloat', + 'JObjectPtr': 'object', + 'JThrowablePtr': 'object', + 'JStringPtr': 'object', + 'JClassPtr': 'value', + 'JFieldIDPtr': 'fieldID', + 'JMethodIDPtr': 'methodID', + 'ffi.Int32': 'integer', + 'ffi.Void': 'check()', + 'JWeakPtr': 'object', + }; + if (mappings.containsKey(cType)) { + return mappings[cType]!; + } + throw 'Unknown return type: $cType'; +} + +String? getGlobalEnvExtensionFunction(Member field, Type? checkedReturnType) { + final fieldType = field.type; + if (fieldType is PointerType && fieldType.child is NativeFunc) { + final nativeFunc = fieldType.child as NativeFunc; + final functionType = nativeFunc.type; + final returnType = functionType.returnType; + var params = functionType.parameters; + if (params.first.name.isEmpty) { + return null; + } + + // Remove env parameter + params = params.sublist(1); + + final signature = params + .map((p) => '${p.type.getDartType(dummyWriter)} ${p.name}') + .join(', '); + + final dartType = + FunctionType(returnType: checkedReturnType!, parameters: params) + .getDartType(dummyWriter); + final callArgs = params.map((p) => p.name).join(', '); + final checkedGetter = getCheckedGetter(returnType); + var returns = returnType.getDartType(dummyWriter); + if (checkedGetter == 'boolean') { + returns = 'bool'; + } + return ''' +late final _${field.name} = + ptr.ref.${field.name}.asFunction<$dartType>();\n +$returns ${field.name}($signature) => + _${field.name}($callArgs).$checkedGetter; + +'''; + } + return null; +} + +void writeDartExtensions(Library library) { + const header = ''' +// ignore_for_file: non_constant_identifier_names +// coverage:ignore-file + +import "dart:ffi" as ffi;\n +import "jni_bindings_generated.dart"; + +'''; + const importAccessors = ''' +import "../accessors.dart"; + +'''; + + final globalEnvExtension = getGlobalEnvExtension(library); + final accessorExtension = getFunctionPointerExtension( + library, + 'JniAccessorsStruct', + 'JniAccessors', + ); + File.fromUri(Paths.globalEnvExts).writeAsStringSync(preamble + + header + + importAccessors + + globalEnvExtension + + accessorExtension); + final localEnvExtsFile = File.fromUri(Paths.localEnvExts); + if (localEnvExtsFile.existsSync()) { + localEnvExtsFile.deleteSync(); + } + if (!writeLocalEnvExtensions) { + return; + } + final envExtension = getFunctionPointerExtension( + library, + 'JniEnv', + 'LocalJniEnv', + indirect: true, + implicitThis: true, + ); + final jvmExtension = getFunctionPointerExtension( + library, + 'JavaVM', + 'JniJavaVM', + indirect: true, + implicitThis: true, + ); + localEnvExtsFile + .writeAsStringSync(preamble + header + envExtension + jvmExtension); +} + +String getGlobalEnvExtension( + Library library, +) { + final env = findCompound(library, localEnvType); + final globalEnv = findCompound(library, globalEnvType); + final checkedReturnTypes = {}; + for (var field in globalEnv.members) { + final fieldType = field.type; + if (fieldType is PointerType && fieldType.child is NativeFunc) { + checkedReturnTypes[field.name] = + (fieldType.child as NativeFunc).type.returnType; + } + } + final extensionFunctions = env.members + .map((m) => getGlobalEnvExtensionFunction(m, checkedReturnTypes[m.name])) + .whereNotNull() + .join('\n'); + return ''' +/// Wraps over Pointer and exposes function pointer fields +/// as methods. +class GlobalJniEnv { + final ffi.Pointer ptr; + GlobalJniEnv(this.ptr); + $extensionFunctions +} +'''; +} + +String? getFunctionPointerExtensionFunction(Member field, + {bool indirect = false, bool implicitThis = false}) { + final fieldType = field.type; + if (fieldType is PointerType && fieldType.child is NativeFunc) { + final nativeFunc = fieldType.child as NativeFunc; + final functionType = nativeFunc.type; + final returnType = functionType.returnType; + final params = functionType.parameters; + if (params.first.name.isEmpty) { + return null; + } + + final visibleParams = implicitThis ? params.sublist(1) : params; + + final signature = visibleParams + .map((p) => '${p.type.getDartType(dummyWriter)} ${p.name}') + .join(', '); + + final dartType = FunctionType(returnType: returnType, parameters: params) + .getDartType(dummyWriter); + final callArgs = [ + if (implicitThis) 'ptr', + ...visibleParams.map((p) => p.name) + ].join(', '); + final returns = returnType.getDartType(dummyWriter); + final dereference = indirect ? 'value.ref' : 'ref'; + return ''' +late final _${field.name} = + ptr.$dereference.${field.name}.asFunction<$dartType>(); +$returns ${field.name}($signature) => _${field.name}($callArgs); + +'''; + } + return null; +} + +String getFunctionPointerExtension( + Library library, String type, String wrapperClassName, + {bool indirect = false, bool implicitThis = false}) { + final typeBinding = + library.bindings.firstWhere((b) => b.name == type) as Type; + final compound = typeBinding.typealiasType.baseType as Compound; + final extensionFunctions = compound.members + .map((f) => getFunctionPointerExtensionFunction(f, + indirect: indirect, implicitThis: implicitThis)) + .whereNotNull() + .join('\n'); + return ''' +/// Wraps over the function pointers in $type and exposes them as methods. +class $wrapperClassName { + final ffi.Pointer<$type> ptr; + $wrapperClassName(this.ptr); + + $extensionFunctions +} + +'''; +} + +void generateDartExtensions(Library library) { + writeDartExtensions(library); + executeDartFormat([Paths.globalEnvExts, Paths.localEnvExts]); +} diff --git a/pkgs/jni/tool/wrapper_generators/logging.dart b/pkgs/jni/tool/wrapper_generators/logging.dart new file mode 100644 index 000000000..386f5c69d --- /dev/null +++ b/pkgs/jni/tool/wrapper_generators/logging.dart @@ -0,0 +1,7 @@ +// Copyright (c) 2023, 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. + +import 'package:logging/logging.dart'; + +final logger = Logger('ffi_wrappers_generator'); diff --git a/pkgs/jni/windows/.gitignore b/pkgs/jni/windows/.gitignore new file mode 100644 index 000000000..b3eb2be16 --- /dev/null +++ b/pkgs/jni/windows/.gitignore @@ -0,0 +1,17 @@ +flutter/ + +# Visual Studio user-specific files. +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual Studio build-related files. +x64/ +x86/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ diff --git a/pkgs/jni/windows/CMakeLists.txt b/pkgs/jni/windows/CMakeLists.txt new file mode 100644 index 000000000..67bbdc687 --- /dev/null +++ b/pkgs/jni/windows/CMakeLists.txt @@ -0,0 +1,23 @@ +# The Flutter tooling requires that developers have a version of Visual Studio +# installed that includes CMake 3.14 or later. You should not increase this +# version, as doing so will cause the plugin to fail to compile for some +# customers of the plugin. +cmake_minimum_required(VERSION 3.14) + +# Project-level configuration. +set(PROJECT_NAME "jni") +project(${PROJECT_NAME} LANGUAGES CXX) + +# Invoke the build for native code shared with the other target platforms. +# This can be changed to accomodate different builds. +add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../src" "${CMAKE_CURRENT_BINARY_DIR}/shared") + +# List of absolute paths to libraries that should be bundled with the plugin. +# This list could contain prebuilt libraries, or libraries created by an +# external build triggered from this build file. +set(jni_bundled_libraries + # Defined in ../src/CMakeLists.txt. + # This can be changed to accomodate different builds. + $ + PARENT_SCOPE +) diff --git a/pkgs/jnigen/.gitignore b/pkgs/jnigen/.gitignore new file mode 100644 index 000000000..a63fd728b --- /dev/null +++ b/pkgs/jnigen/.gitignore @@ -0,0 +1,48 @@ +# See https://www.dartlang.org/guides/libraries/private-files + +# Files and directories created by pub. +.dart_tool/ +.packages +build/ +pubspec.lock +.flutter-plugins +.flutter-plugins-dependencies + +# created by maven +/target/ + +# Directory created by dartdoc. +doc/api/ + +# Avoid committing generated Javascript files: +*.dart.js +*.info.json # Produced by the --dump-info flag. +*.js # When generated by dart2js. Don't specify *.js if your + # project includes source files written in JavaScript. +*.js_ +*.js.deps +*.js.map + +# IDE and debugger files. +.clangd +.gdb_history +.history +.vscode +compile_commands.json + +# IntelliJ +*.iml +*.ipr +*.iws +.idea/ + +# Mac +.DS_Store + +# Vim +.*.swp + +## Downloaded files and build artifacts +*.jar +*.class +*.exe diff --git a/pkgs/jnigen/CHANGELOG.md b/pkgs/jnigen/CHANGELOG.md new file mode 100644 index 000000000..0056f41dc --- /dev/null +++ b/pkgs/jnigen/CHANGELOG.md @@ -0,0 +1,79 @@ +## 0.8.0-wip + +- **Breaking Change**: The generated impl class for interfaces is now an + `interface`. + +## 0.7.0 + +- **Breaking Change** ([#387](https://github.com/dart-lang/jnigen/issues/387)): + Added `JBuffer` and `JByteBuffer` classes as default classes for + `java.nio.Buffer` and `java.nio.ByteBuffer` respectively. +- **Breaking Change**: Made the type classes `final`. +- Added `ignore_for_file: lines_longer_than_80_chars` to the generated file + preamble. +- Added an explicit cast in generated `.implement` code to allow + `dart analyze` to pass when `strict-casts` is set. + +## 0.6.0 + +- **Breaking Change** ([#131](https://github.com/dart-lang/jnigen/issues/131)): + Renamed `delete*` to `release*`. +- **Breaking Change** ([#354](https://github.com/dart-lang/jnigen/issues/354)): + Renamed constructors from `ctor1`, `ctor2`, ... to `new1`, `new2`, ... +- **Breaking Change**: Specifying a class always pulls in nested classes by + default. If a nested class is specified in config, it will be an error. +- **Breaking Change**: Removed `suspend_fun_to_async` flag from the config. It's + now happening by default since we read the Kotlin's metadata and reliably + identify the `suspend fun`s. +- Fixed a bug where the nested classes would be generated incorrectly depending + on the backend used for generation. +- Fixed a bug where ASM backend would produce the incorrect parent for + multi-level nested classes. +- Fixed a bug where the backends would produce different descriptors for the + same method. +- Added `enable_experiment` option to config. +- Created an experiment called `interface_implementation` which creates a + `.implement` method for interfaces, so you can implement them using Dart. +- Save all `jnigen` logs to a file in `.dart_tool/jnigen/logs/`. This is useful + for debugging. + +## 0.5.0 + +- **Breaking Change** ([#72](https://github.com/dart-lang/jnigen/issues/72)): + Removed support for `importMap` in favor of the newly added interop mechanism + with importing yaml files. +- **Breaking Change** ([#72](https://github.com/dart-lang/jnigen/issues/72)): + `java.util.Set`, `java.util.Map`, `java.util.List`, `java.util.Iterator` and + the boxed types like `java.lang.Integer`, `java.lang.Double`, ... will be + generated as their corresponding classes in `package:jni`. +- Strings now use UTF16. + +## 0.4.0 + +- **Breaking Change** ([#145](https://github.com/dart-lang/jnigen/issues/145)): + Type arguments are now named instead of positional. +- Type parameters can now be inferred when possible. +- Fixed a bug where passing a `long` argument truncated it to `int` in pure dart + bindings. +- Removed array extensions from the generated code. +- Added the ability to use source dependencies from Gradle. +- Fixed an issue with the field setter. +- Fixed an issue where exceptions were not properly thrown in pure Dart + bindings. + +## 0.3.0 + +- Added the option to convert Kotlin `suspend fun` to Dart async methods. Add + `suspend_fun_to_async: true` to `jnigen.yaml`. + +## 0.2.0 + +- Support generating bindings for generics. + +## 0.1.1 + +- Windows support for running tests and examples on development machines. + +## 0.1.0 + +- Initial version: Basic bindings generation, maven and android utilities diff --git a/pkgs/jnigen/LICENSE b/pkgs/jnigen/LICENSE new file mode 100644 index 000000000..f0604effe --- /dev/null +++ b/pkgs/jnigen/LICENSE @@ -0,0 +1,32 @@ +Copyright 2022, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Code generated by JNIgen is owned by the owner of the input file used +when generating it. This code is not standalone and requires a +support library to be linked with it. This support library is itself +covered by the above license. diff --git a/pkgs/jnigen/README.md b/pkgs/jnigen/README.md new file mode 100644 index 000000000..eaffeaa4e --- /dev/null +++ b/pkgs/jnigen/README.md @@ -0,0 +1,285 @@ +[![Build Status](https://github.com/dart-lang/jnigen/workflows/Dart%20CI/badge.svg)](https://github.com/dart-lang/jnigen/actions?query=workflow%3A%22Dart+CI%22+branch%3Amain) +[![Coverage Status](https://coveralls.io/repos/github/dart-lang/jnigen/badge.svg?branch=main)](https://coveralls.io/github/dart-lang/jnigen?branch=main) + +## Introduction +Experimental bindings generator for Java bindings through dart:ffi and JNI. + +`jnigen` scans compiled JAR files or Java source code to generate a description of the API, then uses it to generate Dart annd C bindings. The Dart bindings call the C bindings, which in-turn call the Java functions through JNI. Shared functionality and base classes are provided through the support library, `package:jni`. + +The configuration for binding generation is usually provided through YAML. + +Three configuration details are needed to generate the bindings. Everything else is optional: + +* _Inputs_: input can be Java source files (`source_path`), or compiled classes / JARs (`class_path`). Some maven / gradle based tooling is also provided to simplify obtaining dependencies. + +* _Outputs_: Output can be generated in package-structured (one file per class) or single file bindings. Target path to write C and Dart bindings needs to be specified. + +* _Classes_: Specify which classes or packages you need bindings for. Specifying a package includes all classes inside it recursively. + +Check out the [examples](jnigen/example/) to see some sample configurations. + +C code is always generated into a directory with it's own build configuration. It's built as a separate dynamic library. + +Lastly, [dart_only bindings](#pure-dart-bindings) mode is also available as a proof-of-concept. It does not need intermediate C bindings, only a dependency on the support library `package:jni`. + +## Example +It's possible to generate bindings for JAR libraries, or Java source files. + +Here's a simple example Java file, in a Flutter Android app. + +```java +package com.example.in_app_java; + +import android.app.Activity; +import android.widget.Toast; +import androidx.annotation.Keep; + +@Keep +public abstract class AndroidUtils { + // Hide constructor + private AndroidUtils() {} + + public static void showToast(Activity mainActivity, CharSequence text, int duration) { + mainActivity.runOnUiThread(() -> Toast.makeText(mainActivity, text, duration).show()); + } +} +``` + +This produces the following boilerplate: + +#### Dart Bindings: + +```dart +/// Some boilerplate is omitted for clarity. +final ffi.Pointer Function(String sym) jniLookup = + ProtectedJniExtensions.initGeneratedLibrary("android_utils"); + +/// from: com.example.in_app_java.AndroidUtils +class AndroidUtils extends jni.JObject { + AndroidUtils.fromRef(ffi.Pointer ref) : super.fromRef(ref); + + static final _showToast = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer, ffi.Int32)>>("AndroidUtils__showToast") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer, int)>(); + + /// from: static public void showToast(android.app.Activity mainActivity, java.lang.CharSequence text, int duration) + static void showToast( + jni.JObject mainActivity, jni.JObject text, int duration) => + _showToast(mainActivity.reference, text.reference, duration).check(); +} +``` + +#### C Bindings: + +```c +// Some boilerplate is omitted for clarity. + +// com.example.in_app_java.AndroidUtils +jclass _c_AndroidUtils = NULL; + +jmethodID _m_AndroidUtils__showToast = NULL; +FFI_PLUGIN_EXPORT +JniResult AndroidUtils__showToast(jobject mainActivity, + jobject text, + int32_t duration) { + load_env(); + load_class_gr(&_c_AndroidUtils, "com/example/in_app_java/AndroidUtils"); + if (_c_AndroidUtils == NULL) + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_AndroidUtils, &_m_AndroidUtils__showToast, "showToast", + "(Landroid/app/Activity;Ljava/lang/CharSequence;I)V"); + if (_m_AndroidUtils__showToast == NULL) + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallStaticVoidMethod(jniEnv, _c_AndroidUtils, + _m_AndroidUtils__showToast, mainActivity, + text, duration); + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; +} +``` + +The YAML configuration used to generate the above code looks like this: + +```yaml +android_sdk_config: + add_gradle_deps: true + +output: + c: + library_name: android_utils + path: src/android_utils/ + dart: + path: lib/android_utils.dart + structure: single_file + +source_path: + - 'android/app/src/main/java' +classes: + - 'com.example.in_app_java.AndroidUtils' +``` + +The complete example can be found in [jnigen/example/in_app_java](jnigen/example/in_app_java), which adds few more classes to demonstrate using classes from gradle JAR and source dependencies. + +## Supported platforms +| Platform | Dart Standalone | Flutter | +| -------- | --------------- | ------------- | +| Android | n/a | Supported | +| Linux | Supported | Supported | +| Windows | Supported | Supported | +| MacOS | Supported | Not Yet | + +On Android, the flutter application runs embedded in Android JVM. On other platforms, a JVM needs to be explicitly spawned using `Jni.spawn`. `package:jni` provides the infrastructure for initializing and managing the JNI on both Android and Non-Android platforms. + +## Java features support +Currently basic features of the Java language are supported in the bindings. Each Java class is mapped to a Dart class. Bindings are generated for methods, constructors and fields. Exceptions thrown in Java are rethrown in Dart with stack trace from Java. + +More advanced features such as callbacks are not supported yet. Support for these features is tracked in the [issue tracker](https://github.com/dart-lang/jnigen/issues). + +## Note on Dart (standalone) target +`package:jni` is an FFI plugin containing native code, and any bindings generated from jnigen contains native code too. + +On Flutter targets, native libraries are built automatically and bundled. On standalone platforms, no such infrastructure exists yet. As a stopgap solution, running `dart run jni:setup` in a target directory builds all JNI native dependencies of the package into `build/jni_libs`. + +By default `jni:setup` goes through pubspec configuration and builds all JNI dependencies of the project. It can be overridden to build a custom directory using `-s` switch, which can be useful when output configuration for C bindings does not follow standard FFI plugin layout. + +The build directory has to be passed to `Jni.spawn` call. It's assumed that all dependencies are built into the same target directory, so that once JNI is initialized, generated bindings can load their respective C libraries automatically. + +## Requirements +### SDK +Flutter SDK is required. + +Dart standalone target is supported, but due to some problems with pubspec format, the `dart` command must be from Flutter SDK and not Dart SDK. See [dart-lang/pub#3563](https://github.com/dart-lang/pub/issues/3563). + +### Java tooling + +**Use JDK versions 11 to 17. The newer versions will not work because of their lack of [compatibility](https://docs.gradle.org/current/userguide/compatibility.html) with Gradle.** + +Along with JDK, maven (`mvn` command) is required. On windows, it can be installed using a package manager such as [chocolatey](https://community.chocolatey.org/packages/maven) or [scoop](https://scoop.sh/#/apps?q=maven). + +__On windows, append the path of `jvm.dll` in your JDK installation to PATH.__ + +For example, on Powershell: + +```powershell +$env:Path += ";${env:JAVA_HOME}\bin\server". +``` + +If JAVA_HOME not set, find the `java.exe` executable and set the environment variable in Control Panel. If java is installed through a package manager, there may be a more automatic way to do this. (Eg: `scoop reset`). + +### C/C++ tooling +CMake and a standard C toolchain are required to build `package:jni` and C bindings generated by `jnigen`. + +It's recommended to have `clang-format` installed for formatting the generated C bindings. On Windows, it's part of LLVM installation. On most Linux distributions it is available as a separate package. On MacOS, it can be installed using Homebrew. + +## FAQs + +#### I am getting ClassNotFoundError at runtime. +`jnigen` does not handle getting the classes into application. It has to be done by target-specific mechanism. Such as adding a gradle dependency on Android, or manually providing classpath to `Jni.spawn` on desktop / standalone targets. + +On Android, `proguard` prunes classes which it deems inaccessible. Since JNI class lookup happens in runtime, this leads to ClassNotFound errors in release mode even if the dependency is included in gradle. [in_app_java example](jnigen/example/in_app_java/) discusses two mechanisms to prevent this: using `Keep` annotation (`androidx.annotation.Keep`) for the code written in the application itself, and [proguard-rules file](jnigen/example/in_app_java/android/app/proguard-rules.pro) for external libraries. + +Lastly, some libraries such as `java.awt` do not exist in android. Attempting to use libraries which depend on them can also lead to ClassNotFound errors. + +#### `jnigen` is not finding classes. +Ensure you are providing correct source and class paths, and they follow standard directory structure. If your class name is `com.abc.MyClass`, `MyClass` must be in `com/abc/MyClass.java` relative to one of the source paths, or `com/abc/MyClass.class` relative to one of the class paths specified in YAML. + +If the classes are in JAR file, make sure to provide path to JAR file itself, and not the containing directory. + +#### `jnigen` is unable to parse sources. +If the errors are similar to `symbol not found`, ensure all dependencies of the source are available. If such dependency is compiled, it can be included in `class_path`. + +#### How are classes mapped into bindings? +Each Java class generates a subclass of `JObject` class, which wraps a `jobject` reference in JNI. Nested classes use `_` as separator, `Example.NestedClass` will be mapped to `Example_NestedClass`. + +#### Does `JObject` hold a local or global reference? Does it need to be manually released? +Each Java object returned into Dart creates a JNI global reference. Reference deletion is taken care of by `NativeFinalizer` and that's usually sufficient. + +It's a good practice to keep the interface between languages sparse. However, if there's a need to create several references (Eg: in a loop), you can use FFI Arena mechanism (`using` function) and `releasedBy` method, or manually release the object using `release` method. + +#### Should I use `jnigen` over Method channels? +This is currently an experimental package. Many features are missing, and it's rough around the edges. You're welcome to try it and give feedback. + +## YAML Configuration Reference +Keys ending with a colon (`:`) denote subsections. + +The typical invocation with YAML configuration is + +``` +dart run jnigen --config jnigen.yaml +``` + +Any configuration can be overridden through command line using `-D` or `--override` switch. For example `-Dlog_level=warning` or `-Dsummarizer.backend=asm`. (Use `.` to separate subsection and property name). + +A `*` denotes required configuration. + +| Configuration property | Type / Values | Description | +| ---------------------- | ------------- | ----------------------------------------------------------------------- | +| `preamble` | Text | Text to be pasted in the start of each generated file. | +| `source_path` | List of directory paths | Directories to search for source files. Note: source_path for dependencies downloaded using `maven_downloads` configuration is added automatically without the need to specify here. | +| `class_path` | List of directory / JAR paths | Classpath for API summary generation. This should include any JAR dependencies of the source files in `source_path`. | +| `classes` * | List of qualified class / package names | List of qualified class / package names. `source_path` will be scanned assuming the sources follow standard java-ish hierarchy. That is a.b.c either maps to a directory `a/b/c` or a class file `a/b/c.java`. | +| `enable_experiment` | List of experiment names:
  • `interface_implementation`
| List of enabled experiments. These features are still in development and their API might break. | +| `output:` | (Subsection) | This subsection will contain configuration related to output files. | +| `output:` >> `bindings_type` | `c_based` (default) or `dart_only` | Binding generation strategy. [Trade-offs](#pure-dart-bindings) are explained at the end of this document. | +| `output:` >> `c:` | (Subsection) | This subsection specified C output configuration. Required if `bindings_type` is `c_based`. | +| `output:` >> `c:` >> path * | Directory path | Directory to write C bindings. Usually `src/` in case of an FFI plugin template. | +| `output:` >> `c:` >> subdir | Directory path | If specified, C bindings will be written to `subdir` resolved relative to `path`. This is useful when bindings are supposed to be under source's license, and written to a subdirectory such as `third_party`. | +| `output:` >> `c:` >> `library_name` *| Identifier (snake_case) | Name for generated C library. +| `output:` >> `dart:` | (Subsection) | This subsection specifies Dart output configuration. | +| `output:` >> `dart:` >> `structure` | `package_structure` / `single_file` | Whether to map resulting dart bindings to file-per-class source layout, or write all bindings to single file. +| `output:` >> `dart:` >> `path` * | Directory path or File path | Path to write Dart bindings. Should end in `.dart` for `single_file` configurations, and end in `/` for `package_structure` (default) configuration. | +| `maven_downloads:` | (Subsection) | This subsection will contain configuration for automatically downloading Java dependencies (source and JAR) through maven. | +| `maven_downloads:` >> `source_deps` | List of maven package coordinates | Source packages to download and unpack using maven. The names should be valid maven artifact coordinates. (Eg: `org.apache.pdfbox:pdfbox:2.0.26`). The downloads do not include transitive dependencies. | +| `maven_downloads:` >> `source_dir` | Path | Directory in which maven sources are extracted. Defaults to `mvn_java`. It's not required to list this explicitly in source_path. | +| `maven_downloads:` >> `jar_only_deps` | List of maven package coordinates | JAR dependencies to download which are not mandatory transitive dependencies of `source_deps`. Often, it's required to find and include optional dependencies so that entire source is valid for further processing. | +| `maven_downloads:` >> `jar_dir` | Path | Directory to store downloaded JARs. Defaults to `mvn_jar`. | +| `log_level` | Logging level | Configure logging level. Defaults to `info`. | +| `android_sdk_config:` | (Subsection) | Configuration for autodetection of Android dependencies and SDK. Note that this is more experimental than others, and very likely subject to change. | +| `android_sdk_config:` >> `add_gradle_deps` | Boolean | If true, run a gradle stub during `jnigen` invocation, and add Android compile classpath to the classpath of jnigen. This requires a release build to have happened before, so that all dependencies are cached appropriately. | +| `android_sdk_config:` >> `android_example` | Directory path | In case of an Android plugin project, the plugin itself cannot be built and `add_gradle_deps` is not directly feasible. This property can be set to relative path of package example app (usually `example/` so that gradle dependencies can be collected by running a stub in this directory. See [notification_plugin example](jnigen/example/notification_plugin/jnigen.yaml) for an example. | +| `summarizer:` | (Subsection) | Configuration specific to summarizer component, which builds API descriptions from Java sources or JAR files. | +| `summarizer:` >> `backend` | `auto`, `doclet` or `asm` | Specifies the backend to use in API summary generation. `doclet` uses OpenJDK Doclet API to build summary from sources. `asm` uses ASM library to build summary from classes in `class_path` JARs. `auto` attempts to find the class in sources, and falls back to using ASM. | +| `summarizer:` >> `extra_args` (DEV) | List of CLI arguments | Extra arguments to pass to summarizer JAR. | +| `exclude:` | (Subsection) | Exclude methods or fields using regex filters. It's generally useful to exclude problematic fields or methods which, with current binding generation, can lead to syntax errors | +| `exclude:` >> `methods`| List of methods in `classBinaryName#methodName` format where classBinaryName is same as qualified name, but `$` preceding a nested class instead of `.`. Example: `com.example.MyClass` or `com.example.MyClass$NestedClass` | Methods to exclude. +| `exclude:` >> `fields` | List of fields in `classBinaryName#fieldName` format | Fields to exclude. + +It's possible to use the programmatic API instead of YAML. + +* Create a tool script. (Eg: `tool/generate_jni_bindings.dart`) +* import `package:jnigen/jnigen.dart` +* construct a `Config` object and pass it to `generateJniBindings` function. The parameters are similar to the ones described above. + +## Pure dart Bindings +It's possible to generate bindings that do not rely on an intermediate layer of C code. Bindings will still depend on `package:jni` and its support library written in C. But this approach avoids large C bindings. + +To enable pure dart bindings, specify +``` +output: + bindings_type: dart_only +``` + +Any C output configuration will be ignored. + +However, pure dart bindings will require additional allocations and check runtimeType of the arguments. This will be the case until Variadic arguments land in Dart FFI. + +## Android core libraries +These days, Android projects depend heavily on AndroidX and other libraries downloaded via gradle. We have a tracking issue to improve detection of android SDK and dependencies. (#31). Currently we can fetch the JAR dependencies of an android project, by running a gradle stub, if `android_sdk_config` >> `add_gradle_deps` is specified. + +But core libraries (the `android.**` namespace) are not downloaded through gradle. The core libraries are shipped as stub JARs with the Android SDK. (`$SDK_ROOT/platforms/android-$VERSION/android-stubs-src.jar`). + +Currently we don't have an automatic mechanism for using these. You can unpack this JAR manually into some directory and provide it as a source path. + +However there are 2 caveats to this caveat. + +* SDK stubs after version 28 are incomplete. OpenJDK Doclet API we use to generate API summaries will error on incomplete sources. +* The API can't process the `java.**` namespaces in the Android SDK stubs, because it expects a module layout. So if you want to generate bindings for, say, `java.lang.Math`, you cannot use the Android SDK stubs. OpenJDK sources can be used instead. + +The JAR files (`$SDK_ROOT/platforms/android-$VERSION/android.jar`) can be used instead. But compiled JARs do not include JavaDoc and method parameter names. This JAR is automatically included by Gradle when `android_sdk_config` >> `add_gradle_deps` is specified. + +## Contributing +See the wiki for architecture-related documents. + diff --git a/pkgs/jnigen/analysis_options.yaml b/pkgs/jnigen/analysis_options.yaml new file mode 100644 index 000000000..4bebf0eb6 --- /dev/null +++ b/pkgs/jnigen/analysis_options.yaml @@ -0,0 +1,19 @@ +# 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. + +include: package:lints/recommended.yaml + +analyzer: + exclude: [build/**, example/**] + language: + strict-raw-types: true + strict-inference: true + +linter: + rules: + - prefer_final_locals + - prefer_const_declarations + - unawaited_futures + - prefer_const_constructors + - prefer_relative_imports diff --git a/pkgs/jnigen/android_test_runner/.gitignore b/pkgs/jnigen/android_test_runner/.gitignore new file mode 100644 index 000000000..24476c5d1 --- /dev/null +++ b/pkgs/jnigen/android_test_runner/.gitignore @@ -0,0 +1,44 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/pkgs/jnigen/android_test_runner/.metadata b/pkgs/jnigen/android_test_runner/.metadata new file mode 100644 index 000000000..957ea81cf --- /dev/null +++ b/pkgs/jnigen/android_test_runner/.metadata @@ -0,0 +1,30 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled. + +version: + revision: f72efea43c3013323d1b95cff571f3c1caa37583 + channel: stable + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: f72efea43c3013323d1b95cff571f3c1caa37583 + base_revision: f72efea43c3013323d1b95cff571f3c1caa37583 + - platform: android + create_revision: f72efea43c3013323d1b95cff571f3c1caa37583 + base_revision: f72efea43c3013323d1b95cff571f3c1caa37583 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/pkgs/jnigen/android_test_runner/README.md b/pkgs/jnigen/android_test_runner/README.md new file mode 100644 index 000000000..cd85e199b --- /dev/null +++ b/pkgs/jnigen/android_test_runner/README.md @@ -0,0 +1,17 @@ +## What's this? + +This is Flutter app project which serves as a skeleton for running binding runtime tests on android, using Flutter's integration testing mechanism. + +## How to run tests? + +Generate runtime test files, by running the following in parent (jnigen) directory. + +```bash +dart run tool/generate_runtime_tests.dart +``` + +This will generate integration_test/runtime_test.dart in this directory, along with other runtime tests for `jnigen`. This can be run with regular integration test mechanism. + +```bash +flutter test integration_test/ +``` \ No newline at end of file diff --git a/pkgs/jnigen/android_test_runner/analysis_options.yaml b/pkgs/jnigen/android_test_runner/analysis_options.yaml new file mode 100644 index 000000000..61b6c4de1 --- /dev/null +++ b/pkgs/jnigen/android_test_runner/analysis_options.yaml @@ -0,0 +1,29 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/pkgs/jnigen/android_test_runner/android/.gitignore b/pkgs/jnigen/android_test_runner/android/.gitignore new file mode 100644 index 000000000..6f568019d --- /dev/null +++ b/pkgs/jnigen/android_test_runner/android/.gitignore @@ -0,0 +1,13 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties +**/*.keystore +**/*.jks diff --git a/pkgs/jnigen/android_test_runner/android/app/.gitignore b/pkgs/jnigen/android_test_runner/android/app/.gitignore new file mode 100644 index 000000000..df2fa1737 --- /dev/null +++ b/pkgs/jnigen/android_test_runner/android/app/.gitignore @@ -0,0 +1 @@ +.cxx \ No newline at end of file diff --git a/pkgs/jnigen/android_test_runner/android/app/CMakeLists.txt b/pkgs/jnigen/android_test_runner/android/app/CMakeLists.txt new file mode 100644 index 000000000..7bc2474de --- /dev/null +++ b/pkgs/jnigen/android_test_runner/android/app/CMakeLists.txt @@ -0,0 +1,10 @@ +## Parent CMake for Android native build target. This will build +## all C bindings from tests. + +cmake_minimum_required(VERSION 3.10) + +project(simple_package VERSION 0.0.1 LANGUAGES C) + +add_subdirectory(../../../test/jackson_core_test/third_party/c_based/c_bindings jackson_core_test_build) +add_subdirectory(../../../test/simple_package_test/c_based/c_bindings simple_package_test_build) +add_subdirectory(../../../test/kotlin_test/c_based/c_bindings kotlin_test_build) diff --git a/pkgs/jnigen/android_test_runner/android/app/build.gradle b/pkgs/jnigen/android_test_runner/android/app/build.gradle new file mode 100644 index 000000000..58cd27a4c --- /dev/null +++ b/pkgs/jnigen/android_test_runner/android/app/build.gradle @@ -0,0 +1,79 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new FileNotFoundException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion flutter.compileSdkVersion + ndkVersion flutter.ndkVersion + + compileOptions { + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + main.java.srcDirs += '../../../test/simple_package_test/java' + main.java.srcDirs += '../../../test/kotlin_test/kotlin/src/main' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.github.dart_lang.jnigen.android_integration_test" + // You can update the following values to match your application needs. + // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. + minSdkVersion flutter.minSdkVersion + targetSdkVersion flutter.targetSdkVersion + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } + externalNativeBuild { + cmake { + path 'CMakeLists.txt' + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation "com.fasterxml.jackson.core:jackson-core:2.13.4" +} diff --git a/pkgs/jnigen/android_test_runner/android/app/src/debug/AndroidManifest.xml b/pkgs/jnigen/android_test_runner/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 000000000..fc7efb6f4 --- /dev/null +++ b/pkgs/jnigen/android_test_runner/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,8 @@ + + + + diff --git a/pkgs/jnigen/android_test_runner/android/app/src/main/AndroidManifest.xml b/pkgs/jnigen/android_test_runner/android/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..84209fb25 --- /dev/null +++ b/pkgs/jnigen/android_test_runner/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + diff --git a/pkgs/jnigen/android_test_runner/android/app/src/main/kotlin/com/github/dart_lang/jnigen/android_integration_test/MainActivity.kt b/pkgs/jnigen/android_test_runner/android/app/src/main/kotlin/com/github/dart_lang/jnigen/android_integration_test/MainActivity.kt new file mode 100644 index 000000000..5197ccced --- /dev/null +++ b/pkgs/jnigen/android_test_runner/android/app/src/main/kotlin/com/github/dart_lang/jnigen/android_integration_test/MainActivity.kt @@ -0,0 +1,6 @@ +package com.github.dart_lang.jnigen.android_integration_test + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} diff --git a/pkgs/jnigen/android_test_runner/android/app/src/main/res/drawable-v21/launch_background.xml b/pkgs/jnigen/android_test_runner/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 000000000..f74085f3f --- /dev/null +++ b/pkgs/jnigen/android_test_runner/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/pkgs/jnigen/android_test_runner/android/app/src/main/res/drawable/launch_background.xml b/pkgs/jnigen/android_test_runner/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 000000000..304732f88 --- /dev/null +++ b/pkgs/jnigen/android_test_runner/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/pkgs/jnigen/android_test_runner/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/pkgs/jnigen/android_test_runner/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..db77bb4b7 Binary files /dev/null and b/pkgs/jnigen/android_test_runner/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/pkgs/jnigen/android_test_runner/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/pkgs/jnigen/android_test_runner/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..17987b79b Binary files /dev/null and b/pkgs/jnigen/android_test_runner/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/pkgs/jnigen/android_test_runner/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/pkgs/jnigen/android_test_runner/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..09d439148 Binary files /dev/null and b/pkgs/jnigen/android_test_runner/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/pkgs/jnigen/android_test_runner/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/pkgs/jnigen/android_test_runner/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..d5f1c8d34 Binary files /dev/null and b/pkgs/jnigen/android_test_runner/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/pkgs/jnigen/android_test_runner/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/pkgs/jnigen/android_test_runner/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..4d6372eeb Binary files /dev/null and b/pkgs/jnigen/android_test_runner/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/pkgs/jnigen/android_test_runner/android/app/src/main/res/values-night/styles.xml b/pkgs/jnigen/android_test_runner/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 000000000..06952be74 --- /dev/null +++ b/pkgs/jnigen/android_test_runner/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/pkgs/jnigen/android_test_runner/android/app/src/main/res/values/styles.xml b/pkgs/jnigen/android_test_runner/android/app/src/main/res/values/styles.xml new file mode 100644 index 000000000..cb1ef8805 --- /dev/null +++ b/pkgs/jnigen/android_test_runner/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/pkgs/jnigen/android_test_runner/android/app/src/profile/AndroidManifest.xml b/pkgs/jnigen/android_test_runner/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 000000000..fc7efb6f4 --- /dev/null +++ b/pkgs/jnigen/android_test_runner/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,8 @@ + + + + diff --git a/pkgs/jnigen/android_test_runner/android/build.gradle b/pkgs/jnigen/android_test_runner/android/build.gradle new file mode 100644 index 000000000..58a8c74b1 --- /dev/null +++ b/pkgs/jnigen/android_test_runner/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.7.10' + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:7.2.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/pkgs/jnigen/android_test_runner/android/gradle.properties b/pkgs/jnigen/android_test_runner/android/gradle.properties new file mode 100644 index 000000000..94adc3a3f --- /dev/null +++ b/pkgs/jnigen/android_test_runner/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true diff --git a/pkgs/jnigen/android_test_runner/android/gradle/wrapper/gradle-wrapper.properties b/pkgs/jnigen/android_test_runner/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..3c472b99c --- /dev/null +++ b/pkgs/jnigen/android_test_runner/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip diff --git a/pkgs/jnigen/android_test_runner/android/settings.gradle b/pkgs/jnigen/android_test_runner/android/settings.gradle new file mode 100644 index 000000000..44e62bcf0 --- /dev/null +++ b/pkgs/jnigen/android_test_runner/android/settings.gradle @@ -0,0 +1,11 @@ +include ':app' + +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() + +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/pkgs/jnigen/android_test_runner/integration_test/.gitignore b/pkgs/jnigen/android_test_runner/integration_test/.gitignore new file mode 100644 index 000000000..af7c365a2 --- /dev/null +++ b/pkgs/jnigen/android_test_runner/integration_test/.gitignore @@ -0,0 +1 @@ +runtime_test.dart \ No newline at end of file diff --git a/pkgs/jnigen/android_test_runner/lib/main.dart b/pkgs/jnigen/android_test_runner/lib/main.dart new file mode 100644 index 000000000..da07cdd5b --- /dev/null +++ b/pkgs/jnigen/android_test_runner/lib/main.dart @@ -0,0 +1,52 @@ +import 'package:flutter/material.dart'; + +void main() { + runApp(const MyApp()); +} + +class MyApp extends StatelessWidget { + const MyApp({super.key}); + + // This widget is the root of your application. + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + theme: ThemeData( + // This is the theme of your application. + // + // Try running your application with "flutter run". You'll see the + // application has a blue toolbar. Then, without quitting the app, try + // changing the primarySwatch below to Colors.green and then invoke + // "hot reload" (press "r" in the console where you ran "flutter run", + // or simply save your changes to "hot reload" in a Flutter IDE). + // Notice that the counter didn't reset back to zero; the application + // is not restarted. + primarySwatch: Colors.blue, + ), + home: const MyHomePage(), + ); + } +} + +class MyHomePage extends StatelessWidget { + const MyHomePage({super.key}); + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("Integration test runner"), + ), + body: const Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'This app should be run as flutter integration test', + ), + ], + ), + ), + ); + } +} diff --git a/pkgs/jnigen/android_test_runner/pubspec.yaml b/pkgs/jnigen/android_test_runner/pubspec.yaml new file mode 100644 index 000000000..fccc86e48 --- /dev/null +++ b/pkgs/jnigen/android_test_runner/pubspec.yaml @@ -0,0 +1,94 @@ +name: android_integration_test +description: jnigen integration test runner for android +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +# In Windows, build-name is used as the major, minor, and patch parts +# of the product and file versions while build-number is used as the build suffix. +version: 1.0.0+1 + +environment: + sdk: '>=3.1.0 <4.0.0' + +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. +dependencies: + jni: + path: ../../jni/ + ffi: any + flutter: + sdk: flutter + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.2 + +dev_dependencies: + test: any + flutter_test: + sdk: flutter + integration_test: + sdk: flutter + + # The "flutter_lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # activated in the `analysis_options.yaml` file located at the root of your + # package. See that file for information about deactivating specific lint + # rules and activating additional ones. + flutter_lints: ^2.0.0 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/assets-and-images/#from-packages + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/custom-fonts/#from-packages diff --git a/pkgs/jnigen/bin/download_maven_jars.dart b/pkgs/jnigen/bin/download_maven_jars.dart new file mode 100644 index 000000000..6e5b4b022 --- /dev/null +++ b/pkgs/jnigen/bin/download_maven_jars.dart @@ -0,0 +1,29 @@ +// 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. + +import 'dart:io'; + +import 'package:jnigen/jnigen.dart'; +import 'package:jnigen/tools.dart'; + +/// Downloads maven dependencies downloaded by equivalent jnigen invocation. +/// +/// Useful for running standalone examples on already generated sources. +void main(List args) async { + final config = Config.parseArgs(args); + final mavenDownloads = config.mavenDownloads; + if (mavenDownloads != null) { + await MavenTools.downloadMavenJars( + MavenTools.deps(mavenDownloads.jarOnlyDeps + mavenDownloads.sourceDeps), + mavenDownloads.jarDir); + await Directory(mavenDownloads.jarDir) + .list() + .map((entry) => entry.path) + .where((path) => path.endsWith('.jar')) + .forEach(stdout.writeln); + } else { + stderr.writeln('No maven dependencies found in config.'); + exitCode = 2; + } +} diff --git a/pkgs/jnigen/bin/jnigen.dart b/pkgs/jnigen/bin/jnigen.dart new file mode 100644 index 000000000..8dc69e371 --- /dev/null +++ b/pkgs/jnigen/bin/jnigen.dart @@ -0,0 +1,19 @@ +// 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. + +import 'package:jnigen/jnigen.dart'; +import 'package:jnigen/src/logging/logging.dart'; + +void main(List args) async { + enableLoggingToFile(); + Config config; + try { + config = Config.parseArgs(args); + } on ConfigException catch (e) { + log.fatal(e); + } on FormatException catch (e) { + log.fatal(e); + } + await generateJniBindings(config); +} diff --git a/pkgs/jnigen/bin/setup.dart b/pkgs/jnigen/bin/setup.dart new file mode 100644 index 000000000..54df27771 --- /dev/null +++ b/pkgs/jnigen/bin/setup.dart @@ -0,0 +1,24 @@ +// 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. + +import 'dart:io'; + +import 'package:jnigen/src/logging/logging.dart'; +import 'package:jnigen/src/tools/tools.dart'; +import 'package:logging/logging.dart'; + +void main(List args) async { + bool force = false; + setLoggingLevel(Level.INFO); + if (args.isNotEmpty) { + if (args.length != 1 || args[0] != '-f') { + stderr.writeln('usage: dart run jnigen:setup [-f]'); + stderr.writeln('* -f\trebuild ApiSummarizer jar even if it already ' + 'exists.'); + } else { + force = true; + } + } + await buildSummarizerIfNotExists(force: force); +} diff --git a/pkgs/jnigen/cmake/CMakeLists.txt.tmpl b/pkgs/jnigen/cmake/CMakeLists.txt.tmpl new file mode 100644 index 000000000..d0b8a7378 --- /dev/null +++ b/pkgs/jnigen/cmake/CMakeLists.txt.tmpl @@ -0,0 +1,32 @@ +# jni_native_build (Build with jni:setup. Do not delete this line.) + +# The Flutter tooling requires that developers have CMake 3.10 or later +# installed. You should not increase this version, as doing so will cause +# the plugin to fail to compile for some customers of the plugin. +cmake_minimum_required(VERSION 3.10) + +project({{LIBRARY_NAME}} VERSION 0.0.1 LANGUAGES C) + +add_library({{LIBRARY_NAME}} SHARED + "{{SUBDIR}}/{{LIBRARY_NAME}}.c" +) + +set_target_properties({{LIBRARY_NAME}} PROPERTIES + OUTPUT_NAME "{{LIBRARY_NAME}}" +) + +target_compile_definitions({{LIBRARY_NAME}} PUBLIC DART_SHARED_LIB) + +if(WIN32) + set_target_properties(${TARGET_NAME} PROPERTIES + LINK_FLAGS "/DELAYLOAD:jvm.dll") +endif() + +if (ANDROID) + target_link_libraries({{LIBRARY_NAME}} log) +else() + find_package(Java REQUIRED) + find_package(JNI REQUIRED) + include_directories(${JNI_INCLUDE_DIRS}) + target_link_libraries({{LIBRARY_NAME}} ${JNI_LIBRARIES}) +endif() diff --git a/pkgs/jnigen/cmake/README.md b/pkgs/jnigen/cmake/README.md new file mode 100644 index 000000000..65f9951ba --- /dev/null +++ b/pkgs/jnigen/cmake/README.md @@ -0,0 +1,3 @@ +This directory contains a CMakeLists.txt.tmpl file which will be used to generate build configuration for generated C code. + +`{{LIBRARY_NAME}}` in this template will be replaced by `library_name` configuration parameter. \ No newline at end of file diff --git a/pkgs/jnigen/dart_test.yaml b/pkgs/jnigen/dart_test.yaml new file mode 100644 index 000000000..fdd1587e3 --- /dev/null +++ b/pkgs/jnigen/dart_test.yaml @@ -0,0 +1,14 @@ +## Copyright (c) 2023, 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. + +## This file defines test groups for jnigen. This will be helpful to exclude +## lengthy tests by using -x flag. + +tags: + large_test: + timeout: 2x + summarizer_test: + timeout: 1x + runtime_test: + timeout: 1x diff --git a/pkgs/jnigen/example/README.md b/pkgs/jnigen/example/README.md new file mode 100644 index 000000000..dce00fbd5 --- /dev/null +++ b/pkgs/jnigen/example/README.md @@ -0,0 +1,51 @@ +## jnigen examples + +This directory contains examples on how to use jnigen. + +| Directory | Description | +| ------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | +| [in_app_java](https://github.com/dart-lang/jnigen/tree/main/jnigen/example/in_app_java/) | Demonstrates how to include custom Java code in Flutter application and call that using jnigen | +| [pdfbox_plugin](https://github.com/dart-lang/jnigen/tree/main/jnigen/example/pdfbox_plugin/) | Example of a flutter plugin which provides bindings to Apache PDFBox library. Currently works on Flutter desktop and Dart standalone on linux. | +| [notification_plugin](https://github.com/dart-lang/jnigen/tree/main/jnigen/example/notification_plugin/) | Example of a reusable Flutter plugin with custom Java code which uses Android libraries. | +| [kotlin_plugin](https://github.com/dart-lang/jnigen/tree/main/jnigen/example/kotlin_plugin) | Example of using jnigen to generate bindings for Kotlin. | + +We intend to cover few more use cases in future. + +## Creating a jnigen-based plugin from scratch + +### Dart package (Standalone only) + +- Create dart package, add `jni` as dependency and `jnigen` as dev dependency. +- Write the jnigen config similar to [the one in pdfbox_plugin](https://github.com/dart-lang/jnigen/tree/main/jnigen/example/pdfbox_plugin/jnigen.yaml). +- Generate JNI bindings by running `dart run jnigen --config jnigen.yaml`. + +- In the CLI project which uses this package, add this package, and `jni` as a dependency. +- Run `dart run jni:setup` to build native libraries for JNI base library and jnigen generated package. +- Import the package. See [pdf_info.dart](https://github.com/dart-lang/jnigen/tree/main/jnigen/example/pdfbox_plugin/dart_example/bin/pdf_info.dart) for an example of using JNI from dart standalone. + +### Flutter FFI plugin + +Flutter FFI plugin has the advantage of bundling the required native libraries along with Android / Linux Desktop app. + +To create an FFI plugin with JNI bindings: + +- Create a plugin using `plugin_ffi` template. +- Remove ffigen-specific files and stubs. +- Follow the above steps to generate JNI bindings. The plugin can be used from a flutter project. + +- It may be desirable to generate the bindings into a private directory (Eg: `lib/src/third_party`) and re-export the classes from the top level dart file. + +- To use the plugin from Dart projects as well, comment-out or remove flutter SDK requirements from the pubspec. This is however problematic if you want to publish the package. + +### Android plugin with custom Java code + +- Create an FFI plugin with Android as the only platform. +- Build the example/ Android project using command `flutter build apk`. After a release build is done, jnigen can use a gradle stub to collect compile classpaths. +- Write your custom Java code in `android/src/main/java` hierarchy of the plugin. +- Generate JNI bindings as described above. See [notification_plugin/jnigen.yaml](https://github.com/dart-lang/jnigen/tree/main/jnigen/example/notification_plugin/jnigen.yaml) for example configuration. + +### Pure dart bindings + +With Pure dart bindings PoC, most of the FFI setup steps are not required. For example, a simple flutter package can be created instead of an FFI plugin, since there are no native artifacts to bundle. + +The generated bindings still depend on `package:jni`, therefore running `dart run jni:setup` is still a requirement on standalone target. diff --git a/pkgs/jnigen/example/in_app_java/.gitignore b/pkgs/jnigen/example/in_app_java/.gitignore new file mode 100644 index 000000000..8c640484a --- /dev/null +++ b/pkgs/jnigen/example/in_app_java/.gitignore @@ -0,0 +1,50 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release + +## Generated by build process +android/app/.cxx diff --git a/pkgs/jnigen/example/in_app_java/.metadata b/pkgs/jnigen/example/in_app_java/.metadata new file mode 100644 index 000000000..2544bab1f --- /dev/null +++ b/pkgs/jnigen/example/in_app_java/.metadata @@ -0,0 +1,30 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled. + +version: + revision: f1875d570e39de09040c8f79aa13cc56baab8db1 + channel: stable + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 + base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 + - platform: android + create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 + base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/pkgs/jnigen/example/in_app_java/README.md b/pkgs/jnigen/example/in_app_java/README.md new file mode 100644 index 000000000..13813a821 --- /dev/null +++ b/pkgs/jnigen/example/in_app_java/README.md @@ -0,0 +1,24 @@ +# In-App Java Example + +This example shows how to write custom java code in `android/app/src` and call it using `jnigen` generated bindings. + +#### How to run this example: +* Run `flutter run` to run the app. + +* To regenerate bindings after changing Java code, run `flutter pub run jnigen --config jnigen.yaml`. This requires at least one APK build to have been run before, so that it's possible for `jnigen` to obtain classpaths of Android Gradle libraries. Therefore, once run `flutter build apk` before generating bindings for the first time, or after a `flutter clean`. + +#### General steps +These are general steps to integrate Java code into a flutter project using `jnigen`. + +* Write Java code in suitable package folder, under `android/` subproject of the flutter app. + +* Create A jnigen config like `jnigen.yaml` in this example. + +* Generate bindings using jnigen config. + +* Add an `externalNativeBuild` to gradle script (see `android/app/build.gradle` in this example). + +* Add proguard rules to exclude your custom classes from tree shaking, since they are always accessed reflectively in JNI. + +* Build and run the app. + diff --git a/pkgs/jnigen/example/in_app_java/analysis_options.yaml b/pkgs/jnigen/example/in_app_java/analysis_options.yaml new file mode 100644 index 000000000..61b6c4de1 --- /dev/null +++ b/pkgs/jnigen/example/in_app_java/analysis_options.yaml @@ -0,0 +1,29 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/pkgs/jnigen/example/in_app_java/android/.gitignore b/pkgs/jnigen/example/in_app_java/android/.gitignore new file mode 100644 index 000000000..6f568019d --- /dev/null +++ b/pkgs/jnigen/example/in_app_java/android/.gitignore @@ -0,0 +1,13 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties +**/*.keystore +**/*.jks diff --git a/pkgs/jnigen/example/in_app_java/android/app/build.gradle b/pkgs/jnigen/example/in_app_java/android/app/build.gradle new file mode 100644 index 000000000..59ebf1692 --- /dev/null +++ b/pkgs/jnigen/example/in_app_java/android/app/build.gradle @@ -0,0 +1,82 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new FileNotFoundException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion flutter.compileSdkVersion + ndkVersion flutter.ndkVersion + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.in_app_java" + // You can update the following values to match your application needs. + // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration. + minSdkVersion flutter.minSdkVersion + targetSdkVersion flutter.targetSdkVersion + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } + + externalNativeBuild { + cmake { + path "../../src/android_utils/CMakeLists.txt" + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + + /// Add AndroidX emoji2 library as dependency. + /// We will be using EmojiCompat's GlyphChecker in our flutter example. + def emoji2_version = "1.3.0" + implementation "androidx.emoji2:emoji2:$emoji2_version" +} diff --git a/pkgs/jnigen/example/in_app_java/android/app/proguard-rules.pro b/pkgs/jnigen/example/in_app_java/android/app/proguard-rules.pro new file mode 100644 index 000000000..8eecc4ccf --- /dev/null +++ b/pkgs/jnigen/example/in_app_java/android/app/proguard-rules.pro @@ -0,0 +1,17 @@ +# This is the rules file which prevents `proguard` from aggressively +# removing the classes which appear to be unused, in release mode. +# +# Since JNI is based on runtime lookup for classes, proguard will not have +# a way to know EmojiCompat class in our example is actually used. Therefore +# we have to explicitly list it in this file to prevent the application from +# crashing with ClassNotFoundException. +# +# This doesn't apply to builtin classes, eg: those in `android.` namespace Since +# they are already present on the device. +# For the Java code which is written by yourself, you can add `androidx.annotation.Keep` +# instead. (As done in `AndroidUtils.java`). +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +-keep class androidx.emoji2.text.EmojiCompat { public *; } diff --git a/pkgs/jnigen/example/in_app_java/android/app/src/debug/AndroidManifest.xml b/pkgs/jnigen/example/in_app_java/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 000000000..a09603034 --- /dev/null +++ b/pkgs/jnigen/example/in_app_java/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,8 @@ + + + + diff --git a/pkgs/jnigen/example/in_app_java/android/app/src/main/AndroidManifest.xml b/pkgs/jnigen/example/in_app_java/android/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..e674e57c3 --- /dev/null +++ b/pkgs/jnigen/example/in_app_java/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + diff --git a/pkgs/jnigen/example/in_app_java/android/app/src/main/java/com/example/in_app_java/AndroidUtils.java b/pkgs/jnigen/example/in_app_java/android/app/src/main/java/com/example/in_app_java/AndroidUtils.java new file mode 100644 index 000000000..84be6f19a --- /dev/null +++ b/pkgs/jnigen/example/in_app_java/android/app/src/main/java/com/example/in_app_java/AndroidUtils.java @@ -0,0 +1,19 @@ +// 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.example.in_app_java; + +import android.app.Activity; +import android.widget.Toast; +import androidx.annotation.Keep; + +@Keep +public abstract class AndroidUtils { + // Hide constructor + private AndroidUtils() {} + + public static void showToast(Activity mainActivity, CharSequence text, int duration) { + mainActivity.runOnUiThread(() -> Toast.makeText(mainActivity, text, duration).show()); + } +} diff --git a/pkgs/jnigen/example/in_app_java/android/app/src/main/kotlin/com/example/in_app_java/MainActivity.kt b/pkgs/jnigen/example/in_app_java/android/app/src/main/kotlin/com/example/in_app_java/MainActivity.kt new file mode 100644 index 000000000..c8fde0cc8 --- /dev/null +++ b/pkgs/jnigen/example/in_app_java/android/app/src/main/kotlin/com/example/in_app_java/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.in_app_java + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} diff --git a/pkgs/jnigen/example/in_app_java/android/app/src/main/res/drawable-v21/launch_background.xml b/pkgs/jnigen/example/in_app_java/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 000000000..f74085f3f --- /dev/null +++ b/pkgs/jnigen/example/in_app_java/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/pkgs/jnigen/example/in_app_java/android/app/src/main/res/drawable/launch_background.xml b/pkgs/jnigen/example/in_app_java/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 000000000..304732f88 --- /dev/null +++ b/pkgs/jnigen/example/in_app_java/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/pkgs/jnigen/example/in_app_java/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/pkgs/jnigen/example/in_app_java/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..db77bb4b7 Binary files /dev/null and b/pkgs/jnigen/example/in_app_java/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/pkgs/jnigen/example/in_app_java/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/pkgs/jnigen/example/in_app_java/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..17987b79b Binary files /dev/null and b/pkgs/jnigen/example/in_app_java/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/pkgs/jnigen/example/in_app_java/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/pkgs/jnigen/example/in_app_java/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..09d439148 Binary files /dev/null and b/pkgs/jnigen/example/in_app_java/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/pkgs/jnigen/example/in_app_java/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/pkgs/jnigen/example/in_app_java/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..d5f1c8d34 Binary files /dev/null and b/pkgs/jnigen/example/in_app_java/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/pkgs/jnigen/example/in_app_java/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/pkgs/jnigen/example/in_app_java/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..4d6372eeb Binary files /dev/null and b/pkgs/jnigen/example/in_app_java/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/pkgs/jnigen/example/in_app_java/android/app/src/main/res/values-night/styles.xml b/pkgs/jnigen/example/in_app_java/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 000000000..06952be74 --- /dev/null +++ b/pkgs/jnigen/example/in_app_java/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/pkgs/jnigen/example/in_app_java/android/app/src/main/res/values/styles.xml b/pkgs/jnigen/example/in_app_java/android/app/src/main/res/values/styles.xml new file mode 100644 index 000000000..cb1ef8805 --- /dev/null +++ b/pkgs/jnigen/example/in_app_java/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/pkgs/jnigen/example/in_app_java/android/app/src/profile/AndroidManifest.xml b/pkgs/jnigen/example/in_app_java/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 000000000..a09603034 --- /dev/null +++ b/pkgs/jnigen/example/in_app_java/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,8 @@ + + + + diff --git a/pkgs/jnigen/example/in_app_java/android/build.gradle b/pkgs/jnigen/example/in_app_java/android/build.gradle new file mode 100644 index 000000000..2fbab8036 --- /dev/null +++ b/pkgs/jnigen/example/in_app_java/android/build.gradle @@ -0,0 +1,32 @@ +buildscript { + ext.kotlin_version = '1.6.10' + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:7.1.2' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} + +subprojects { + project.evaluationDependsOn(':app') +} + +tasks.register("clean", Delete) { + delete rootProject.buildDir +} diff --git a/pkgs/jnigen/example/in_app_java/android/gradle.properties b/pkgs/jnigen/example/in_app_java/android/gradle.properties new file mode 100644 index 000000000..94adc3a3f --- /dev/null +++ b/pkgs/jnigen/example/in_app_java/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true diff --git a/pkgs/jnigen/example/in_app_java/android/gradle/wrapper/gradle-wrapper.properties b/pkgs/jnigen/example/in_app_java/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..cc5527d78 --- /dev/null +++ b/pkgs/jnigen/example/in_app_java/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip diff --git a/pkgs/jnigen/example/in_app_java/android/settings.gradle b/pkgs/jnigen/example/in_app_java/android/settings.gradle new file mode 100644 index 000000000..44e62bcf0 --- /dev/null +++ b/pkgs/jnigen/example/in_app_java/android/settings.gradle @@ -0,0 +1,11 @@ +include ':app' + +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() + +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/pkgs/jnigen/example/in_app_java/jnigen.yaml b/pkgs/jnigen/example/in_app_java/jnigen.yaml new file mode 100644 index 000000000..f053698ac --- /dev/null +++ b/pkgs/jnigen/example/in_app_java/jnigen.yaml @@ -0,0 +1,20 @@ +android_sdk_config: + add_gradle_deps: true + add_gradle_sources: true + +output: + c: + library_name: android_utils + path: src/android_utils/ + dart: + path: lib/android_utils.dart + structure: single_file + +source_path: + - 'android/app/src/main/java' +classes: + - 'com.example.in_app_java.AndroidUtils' # from source_path + - 'androidx.emoji2.text.EmojiCompat' # From gradle's source path + - 'androidx.emoji2.text.DefaultEmojiCompatConfig' # From gradle's source path + - 'android.os.Build' # from gradle's compile classpath + - 'java.util.HashMap' # 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 new file mode 100644 index 000000000..8eba9cc8e --- /dev/null +++ b/pkgs/jnigen/example/in_app_java/lib/android_utils.dart @@ -0,0 +1,3655 @@ +// Autogenerated by jnigen. DO NOT EDIT! + +// ignore_for_file: annotate_overrides +// ignore_for_file: camel_case_extensions +// ignore_for_file: camel_case_types +// ignore_for_file: constant_identifier_names +// ignore_for_file: file_names +// ignore_for_file: lines_longer_than_80_chars +// ignore_for_file: no_leading_underscores_for_local_identifiers +// ignore_for_file: non_constant_identifier_names +// ignore_for_file: overridden_fields +// ignore_for_file: unnecessary_cast +// ignore_for_file: unused_element +// ignore_for_file: unused_field +// ignore_for_file: unused_import +// ignore_for_file: unused_local_variable +// ignore_for_file: unused_shown_name + +import "dart:isolate" show ReceivePort; +import "dart:ffi" as ffi; +import "package:jni/internal_helpers_for_jnigen.dart"; +import "package:jni/jni.dart" as jni; + +// Auto-generated initialization code. + +final ffi.Pointer Function(String sym) jniLookup = + ProtectedJniExtensions.initGeneratedLibrary("android_utils"); + +/// from: com.example.in_app_java.AndroidUtils +class AndroidUtils extends jni.JObject { + @override + late final jni.JObjType $type = type; + + AndroidUtils.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $AndroidUtilsType(); + static final _showToast = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer, ffi.Int32)>>("AndroidUtils__showToast") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer, int)>(); + + /// from: static public void showToast(android.app.Activity mainActivity, java.lang.CharSequence text, int duration) + static void showToast( + jni.JObject mainActivity, + jni.JObject text, + int duration, + ) { + return _showToast(mainActivity.reference, text.reference, duration).check(); + } +} + +final class $AndroidUtilsType extends jni.JObjType { + const $AndroidUtilsType(); + + @override + String get signature => r"Lcom/example/in_app_java/AndroidUtils;"; + + @override + AndroidUtils fromRef(jni.JObjectPtr ref) => AndroidUtils.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($AndroidUtilsType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($AndroidUtilsType) && + other is $AndroidUtilsType; + } +} + +/// from: androidx.emoji2.text.EmojiCompat +/// +/// Main class to keep Android devices up to date with the newest emojis by adding EmojiSpans +/// to a given CharSequence. +///

+/// By default, EmojiCompat is initialized by EmojiCompatInitializer, which performs +/// deferred font loading to avoid potential app startup delays. The default behavior is to load +/// the font shortly after the first Activity resumes. EmojiCompatInitializer will configure +/// EmojiCompat to use the system emoji font provider via DefaultEmojiCompatConfig and +/// always creates a new background thread for font loading. +///

+/// EmojiCompat will only allow one instance to be initialized and any calls to +/// \#init(Config) after the first one will have no effect. As a result, configuration options +/// may not be provided when using EmojiCompatInitializer. To provide a custom configuration, +/// disable EmojiCompatInitializer in the manifest with: +/// +///

+///     <provider
+///         android:name="androidx.startup.InitializationProvider"
+///         android:authorities="${applicationId}.androidx-startup"
+///         android:exported="false"
+///         tools:node="merge">
+///         <meta-data android:name="androidx.emoji2.text.EmojiCompatInitializer"
+///                   tools:node="remove" />
+///     </provider>
+/// 
+/// +/// When not using EmojiCompatInitializer, EmojiCompat must to be initialized manually using +/// \#init(EmojiCompat.Config). It is recommended to make the initialization as early as +/// possible in your app, such as from Application\#onCreate(). +///

+/// \#init(Config) is fast and may be called from the main thread on the path to +/// displaying the first activity. However, loading the emoji font takes significant resources on a +/// background thread, so it is suggested to use \#LOAD_STRATEGY_MANUAL in all manual +/// configurations to defer font loading until after the first screen displays. Font loading may +/// be started by calling \#load()}. See the implementation EmojiCompatInitializer +/// for ideas when building a manual configuration. +///

+/// After initialization the \#get() function can be used to get the configured instance and +/// the \#process(CharSequence) function can be used to update a CharSequence with emoji +/// EmojiSpans. +///

+///

CharSequence processedSequence = EmojiCompat.get().process("some string")
+///

+/// During loading information about emojis is not available. Before the +/// EmojiCompat instance has finished loading, calls to functions such as EmojiCompat\#process(CharSequence) will throw an exception. It is safe to call process when +/// \#getLoadState() returns \#LOAD_STATE_SUCCEEDED. To register a callback when +/// loading completes use InitCallback. +///

+class EmojiCompat extends jni.JObject { + @override + late final jni.JObjType $type = type; + + EmojiCompat.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $EmojiCompatType(); + + /// from: static public final java.lang.String EDITOR_INFO_METAVERSION_KEY + /// + /// Key in EditorInfo\#extras that represents the emoji metadata version used by the + /// widget. The existence of the value means that the widget is using EmojiCompat. + ///

+ /// If exists, the value for the key is an {@code int} and can be used to query EmojiCompat to + /// see whether the widget has the ability to display a certain emoji using + /// \#hasEmojiGlyph(CharSequence, int). + static const EDITOR_INFO_METAVERSION_KEY = + r"""android.support.text.emoji.emojiCompat_metadataVersion"""; + + /// from: static public final java.lang.String EDITOR_INFO_REPLACE_ALL_KEY + /// + /// Key in EditorInfo\#extras that represents EmojiCompat.Config\#setReplaceAll(boolean) configuration parameter. The key is added only if + /// EmojiCompat is used by the widget. If exists, the value is a boolean. + static const EDITOR_INFO_REPLACE_ALL_KEY = + r"""android.support.text.emoji.emojiCompat_replaceAll"""; + + /// from: static public final int LOAD_STATE_DEFAULT + /// + /// EmojiCompat instance is constructed, however the initialization did not start yet. + ///@see \#getLoadState() + static const LOAD_STATE_DEFAULT = 3; + + /// from: static public final int LOAD_STATE_LOADING + /// + /// EmojiCompat is initializing. + ///@see \#getLoadState() + static const LOAD_STATE_LOADING = 0; + + /// from: static public final int LOAD_STATE_SUCCEEDED + /// + /// EmojiCompat successfully initialized. + ///@see \#getLoadState() + static const LOAD_STATE_SUCCEEDED = 1; + + /// from: static public final int LOAD_STATE_FAILED + /// + /// An unrecoverable error occurred during initialization of EmojiCompat. Calls to functions + /// such as \#process(CharSequence) will fail. + ///@see \#getLoadState() + static const LOAD_STATE_FAILED = 2; + + /// from: static public final int REPLACE_STRATEGY_DEFAULT + /// + /// Replace strategy that uses the value given in EmojiCompat.Config. + ///@see \#process(CharSequence, int, int, int, int) + static const REPLACE_STRATEGY_DEFAULT = 0; + + /// from: static public final int REPLACE_STRATEGY_ALL + /// + /// Replace strategy to add EmojiSpans for all emoji that were found. + ///@see \#process(CharSequence, int, int, int, int) + static const REPLACE_STRATEGY_ALL = 1; + + /// from: static public final int REPLACE_STRATEGY_NON_EXISTENT + /// + /// Replace strategy to add EmojiSpans only for emoji that do not exist in the system. + static const REPLACE_STRATEGY_NON_EXISTENT = 2; + + /// from: static public final int LOAD_STRATEGY_DEFAULT + /// + /// EmojiCompat will start loading metadata when \#init(Config) is called. + ///@see Config\#setMetadataLoadStrategy(int) + static const LOAD_STRATEGY_DEFAULT = 0; + + /// from: static public final int LOAD_STRATEGY_MANUAL + /// + /// EmojiCompat will wait for \#load() to be called by developer in order to + /// start loading metadata. + ///@see Config\#setMetadataLoadStrategy(int) + static const LOAD_STRATEGY_MANUAL = 1; + + /// from: static public final int EMOJI_UNSUPPORTED + /// + /// Result of \#getEmojiMatch(CharSequence, int) that means no part of this codepoint + /// sequence will ever generate an EmojiSpan at the requested metadata level. + /// + /// This return value implies: + /// - EmojiCompat will always defer to system emoji font + /// - System emoji font may or may not support this emoji + /// - This application MAY render this emoji + /// + /// This can be used by keyboards to learn that EmojiCompat does not support this codepoint + /// sequence at this metadata version. The system emoji font is not checked by this method, + /// and this result will be returned even if the system emoji font supports the emoji. This may + /// happen if the application is using an older version of the emoji compat font than the + /// system emoji font. + /// + /// Keyboards may optionally determine that the system emoji font will support the emoji, for + /// example by building a internal lookup table or calling + /// androidx.core.graphics.PaintCompat\#hasGlyph(Paint, String) to query the system + /// emoji font. Keyboards may use a lookup table to optimize this check, however they should be + /// aware that OEMs may add or remove emoji from the system emoji font. + /// + /// Keyboards may finally decide: + /// - If the system emoji font DOES NOT support the emoji, then the emoji IS NOT supported by + /// this application. + /// - If the system emoji font DOES support the emoji, then the emoji IS supported by this + /// application. + /// - If system emoji font is support is UNKNOWN, then assume the emoji IS NOT supported by + /// this application. + static const EMOJI_UNSUPPORTED = 0; + + /// from: static public final int EMOJI_SUPPORTED + /// + /// Result of \#getEmojiMatch(CharSequence, int) that means this codepoint can be drawn + /// by an EmojiSpan at this metadata level. + /// + /// No further checks are required by keyboards for this result. The emoji is always supported + /// by this application. + /// + /// This return value implies: + /// - EmojiCompat can draw this emoji + /// - System emoji font may or may not support this emoji + /// - This application WILL render this emoji + /// + /// This result implies that EmojiCompat can successfully display this emoji. The system emoji + /// font is not checked by this method, and this result may be returned even if the platform + /// also supports the emoji sequence. + /// + /// If the application passes EmojiCompat\#REPLACE_STRATEGY_ALL of true, then an + /// EmojiSpan will always be generated for this emoji. + /// + /// If the application passes EmojiCompat\#REPLACE_STRATEGY_ALL of false, then an + /// EmojiSpan will only be generated if + /// androidx.core.graphics.PaintCompat\#hasGlyph(Paint, String) + /// returns false for this emoji. + static const EMOJI_SUPPORTED = 1; + + /// from: static public final int EMOJI_FALLBACK + /// + /// Result of \#getEmojiMatch(CharSequence, int) that means the full codepoint sequence + /// is not known to emojicompat, but at least one subsequence is an emoji that is known at + /// this metadata level. + /// + /// Keyboards may decide that this emoji is not supported by the application when this result is + /// returned, with no further processing. + /// + /// This return value implies: + /// - EmojiCompat will decompose this ZWJ sequence into multiple glyphs when replaceAll=true + /// - EmojiCompat MAY defer to platform when replaceAll=false + /// - System emoji font may or may not support this emoji + /// - This application MAY render this emoji + /// + /// This return value is only ever returned for ZWJ sequences. To understand this result + /// consider when it may be returned for the multi-skin-tone handshake introduced in emoji 14. + /// + ///

+  ///     U+1FAF1 // unknown @ requested metadata level
+  ///     U+1F3FB // metadata level 1
+  ///     U+200D  // not displayed (ZWJ)
+  ///     U+1FAF2 // unknown @ requested metadata level
+  ///     U+1F3FD // metadata level 1
+  /// 
+ /// + /// In this codepoint sequence, U+1F3FB and U+1F3FD are known from metadata level 1. When an + /// application is using a metadata level that doesn't understand this ZWJ and provides + /// EmojiCompat\#REPLACE_STRATEGY_ALL true, the color emoji are matched and replaced + /// with EmojiSpan. The system emoji font, even if it supports this ZWJ sequence, is + /// never queried and the added EmojiSpans force fallback rendering for the ZWJ sequence. + /// + /// The glyph will only display correctly for this application if ALL of the following + /// requirements are met: + /// - EmojiCompat\#REPLACE_STRATEGY_ALL is false + /// - androidx.core.graphics.PaintCompat\#hasGlyph(Paint, String) returns true for each + /// emoji subsequence known at this metadata level + /// - androidx.core.graphics.PaintCompat\#hasGlyph(Paint, String) returns true for the + /// full sequence + /// + /// Given this return value for the multi-skin-tone handshake above, if + /// EmojiCompat\#REPLACE_STRATEGY_ALL is false then the emoji will display if the + /// entire emoji sequence is matched by + /// androidx.core.graphics.PaintCompat\#hasGlyph(Paint, String) because U+1F3FB and + /// U+1F3FD are both in the system emoji font. + /// + /// Keyboards that wish to determine if the glyph will display correctly by the application in + /// response to this return value should consider building an internal lookup for new ZWJ + /// sequences instead of repeatedly calling + /// androidx.core.graphics.PaintCompat\#hasGlyph(Paint, String) for each emoji + /// subsequence. + static const EMOJI_FALLBACK = 2; + + static final _init = jniLookup< + ffi + .NativeFunction)>>( + "EmojiCompat__init") + .asFunction)>(); + + /// from: static public androidx.emoji2.text.EmojiCompat init(android.content.Context context) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Initialize the singleton instance with the default system-provided configuration. + /// + /// This is the recommended configuration for most applications. For more details see + /// DefaultEmojiCompatConfig. + /// + /// + /// This call will use DefaultEmojiCompatConfig to lookup the default emoji font + /// provider installed on the system and use that, if present. If there is no default font + /// provider onthe system, this call will have no effect. + /// + /// + /// Note: EmojiCompat may only be initialized once, and will return the same instance + /// afterwords. + /// + ///@return Default EmojiCompat for this device, or null if there is no provider on the system. + static EmojiCompat init( + jni.JObject context, + ) { + return const $EmojiCompatType().fromRef(_init(context.reference).object); + } + + static final _init1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("EmojiCompat__init1") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: static public androidx.emoji2.text.EmojiCompat init(android.content.Context context, androidx.emoji2.text.DefaultEmojiCompatConfig.DefaultEmojiCompatConfigFactory defaultFactory) + /// The returned object must be released after use, by calling the [release] method. + /// + /// @hide + static EmojiCompat init1( + jni.JObject context, + DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory defaultFactory, + ) { + return const $EmojiCompatType() + .fromRef(_init1(context.reference, defaultFactory.reference).object); + } + + static final _init2 = jniLookup< + ffi + .NativeFunction)>>( + "EmojiCompat__init2") + .asFunction)>(); + + /// from: static public androidx.emoji2.text.EmojiCompat init(androidx.emoji2.text.EmojiCompat.Config config) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Initialize the singleton instance with a configuration. When used on devices running API 18 + /// or below, the singleton instance is immediately moved into \#LOAD_STATE_SUCCEEDED + /// state without loading any metadata. When called for the first time, the library will create + /// the singleton instance and any call after that will not create a new instance and return + /// immediately. + ///@see EmojiCompat.Config + static EmojiCompat init2( + EmojiCompat_Config config, + ) { + return const $EmojiCompatType().fromRef(_init2(config.reference).object); + } + + static final _isConfigured = + jniLookup>( + "EmojiCompat__isConfigured") + .asFunction(); + + /// from: static public boolean isConfigured() + /// + /// Return true if EmojiCompat has been configured by a successful call to + /// EmojiCompat\#init. + /// + /// You can use this to check if EmojiCompat\#get() will return a valid EmojiCompat + /// instance. + /// + /// This function does not check the \#getLoadState() and will return true even if the + /// font is still loading, or has failed to load. + ///@return true if EmojiCompat has been successfully initialized. + static bool isConfigured() { + return _isConfigured().boolean; + } + + static final _reset = jniLookup< + ffi + .NativeFunction)>>( + "EmojiCompat__reset") + .asFunction)>(); + + /// from: static public androidx.emoji2.text.EmojiCompat reset(androidx.emoji2.text.EmojiCompat.Config config) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Used by the tests to reset EmojiCompat with a new configuration. Every time it is called a + /// new instance is created with the new configuration. + ///@hide + static EmojiCompat reset( + EmojiCompat_Config config, + ) { + return const $EmojiCompatType().fromRef(_reset(config.reference).object); + } + + static final _reset1 = jniLookup< + ffi + .NativeFunction)>>( + "EmojiCompat__reset1") + .asFunction)>(); + + /// from: static public androidx.emoji2.text.EmojiCompat reset(androidx.emoji2.text.EmojiCompat emojiCompat) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Used by the tests to reset EmojiCompat with a new singleton instance. + ///@hide + static EmojiCompat reset1( + EmojiCompat emojiCompat, + ) { + return const $EmojiCompatType() + .fromRef(_reset1(emojiCompat.reference).object); + } + + static final _skipDefaultConfigurationLookup = + jniLookup>( + "EmojiCompat__skipDefaultConfigurationLookup") + .asFunction(); + + /// from: static public void skipDefaultConfigurationLookup(boolean shouldSkip) + /// + /// Reset default configuration lookup flag, for tests. + ///@hide + static void skipDefaultConfigurationLookup( + bool shouldSkip, + ) { + return _skipDefaultConfigurationLookup(shouldSkip ? 1 : 0).check(); + } + + static final _get0 = jniLookup>( + "EmojiCompat__get0") + .asFunction(); + + /// from: static public androidx.emoji2.text.EmojiCompat get() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Return singleton EmojiCompat instance. Should be called after + /// \#init(EmojiCompat.Config) is called to initialize the singleton instance. + ///@return EmojiCompat instance + ///@throws IllegalStateException if called before \#init(EmojiCompat.Config) + static EmojiCompat get0() { + return const $EmojiCompatType().fromRef(_get0().object); + } + + static final _load = jniLookup< + ffi + .NativeFunction)>>( + "EmojiCompat__load") + .asFunction)>(); + + /// from: public void load() + /// + /// When Config\#setMetadataLoadStrategy(int) is set to \#LOAD_STRATEGY_MANUAL, + /// this function starts loading the metadata. Calling the function when + /// Config\#setMetadataLoadStrategy(int) is {@code not} set to + /// \#LOAD_STRATEGY_MANUAL will throw an exception. The load will {@code not} start if: + ///
    + ///
  • the metadata is already loaded successfully and \#getLoadState() is + /// \#LOAD_STATE_SUCCEEDED. + ///
  • + ///
  • a previous load attempt is not finished yet and \#getLoadState() is + /// \#LOAD_STATE_LOADING.
  • + ///
+ ///@throws IllegalStateException when Config\#setMetadataLoadStrategy(int) is not set + /// to \#LOAD_STRATEGY_MANUAL + void load() { + return _load(reference).check(); + } + + static final _registerInitCallback = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("EmojiCompat__registerInitCallback") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void registerInitCallback(androidx.emoji2.text.EmojiCompat.InitCallback initCallback) + /// + /// Registers an initialization callback. If the initialization is already completed by the time + /// the listener is added, the callback functions are called immediately. Callbacks are called on + /// the main looper. + ///

+ /// When used on devices running API 18 or below, InitCallback\#onInitialized() is called + /// without loading any metadata. In such cases InitCallback\#onFailed(Throwable) is never + /// called. + ///@param initCallback the initialization callback to register, cannot be {@code null} + ///@see \#unregisterInitCallback(InitCallback) + void registerInitCallback( + EmojiCompat_InitCallback initCallback, + ) { + return _registerInitCallback(reference, initCallback.reference).check(); + } + + static final _unregisterInitCallback = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>>( + "EmojiCompat__unregisterInitCallback") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void unregisterInitCallback(androidx.emoji2.text.EmojiCompat.InitCallback initCallback) + /// + /// Unregisters a callback that was added before. + ///@param initCallback the callback to be removed, cannot be {@code null} + void unregisterInitCallback( + EmojiCompat_InitCallback initCallback, + ) { + return _unregisterInitCallback(reference, initCallback.reference).check(); + } + + static final _getLoadState = jniLookup< + ffi + .NativeFunction)>>( + "EmojiCompat__getLoadState") + .asFunction)>(); + + /// from: public int getLoadState() + /// + /// Returns loading state of the EmojiCompat instance. When used on devices running API 18 or + /// below always returns \#LOAD_STATE_SUCCEEDED. + ///@return one of \#LOAD_STATE_DEFAULT, \#LOAD_STATE_LOADING, + /// \#LOAD_STATE_SUCCEEDED, \#LOAD_STATE_FAILED + int getLoadState() { + return _getLoadState(reference).integer; + } + + static final _isEmojiSpanIndicatorEnabled = jniLookup< + ffi + .NativeFunction)>>( + "EmojiCompat__isEmojiSpanIndicatorEnabled") + .asFunction)>(); + + /// from: public boolean isEmojiSpanIndicatorEnabled() + /// + /// @return whether a background should be drawn for the emoji for debugging + ///@hide + bool isEmojiSpanIndicatorEnabled() { + return _isEmojiSpanIndicatorEnabled(reference).boolean; + } + + static final _getEmojiSpanIndicatorColor = jniLookup< + ffi + .NativeFunction)>>( + "EmojiCompat__getEmojiSpanIndicatorColor") + .asFunction)>(); + + /// from: public int getEmojiSpanIndicatorColor() + /// + /// @return color of background drawn if EmojiCompat\#isEmojiSpanIndicatorEnabled is true + ///@hide + int getEmojiSpanIndicatorColor() { + return _getEmojiSpanIndicatorColor(reference).integer; + } + + static final _getEmojiStart = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Int32)>>("EmojiCompat__getEmojiStart") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer, int)>(); + + /// from: public int getEmojiStart(java.lang.CharSequence charSequence, int offset) + /// + /// Together with \#getEmojiEnd(CharSequence, int), if the character at {@code offset} is + /// part of an emoji, returns the index range of that emoji, start index inclusively/end index + /// exclusively so that {@code charSequence.subSequence(start, end)} will return that emoji. + /// E.g., getEmojiStart/End("AB\ud83d\ude00", 1) will return (-1,-1) since 'B' is not part an emoji; + /// getEmojiStart/End("AB\ud83d\ude00", 3) will return [2,4), note that "\ud83d\ude00" contains 2 Chars. + /// Returns -1 otherwise. + ///@param charSequence the whole sequence + ///@param offset index of the emoji to look up + ///@return the start index inclusively/end index exclusively + int getEmojiStart( + jni.JObject charSequence, + int offset, + ) { + return _getEmojiStart(reference, charSequence.reference, offset).integer; + } + + static final _getEmojiEnd = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Int32)>>("EmojiCompat__getEmojiEnd") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer, int)>(); + + /// from: public int getEmojiEnd(java.lang.CharSequence charSequence, int offset) + /// + /// see \#getEmojiStart(CharSequence, int). + int getEmojiEnd( + jni.JObject charSequence, + int offset, + ) { + return _getEmojiEnd(reference, charSequence.reference, offset).integer; + } + + static final _handleOnKeyDown = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, ffi.Int32, + ffi.Pointer)>>("EmojiCompat__handleOnKeyDown") + .asFunction< + jni.JniResult Function( + ffi.Pointer, int, ffi.Pointer)>(); + + /// from: static public boolean handleOnKeyDown(android.text.Editable editable, int keyCode, android.view.KeyEvent event) + /// + /// Handles onKeyDown commands from a KeyListener and if {@code keyCode} is one of + /// KeyEvent\#KEYCODE_DEL or KeyEvent\#KEYCODE_FORWARD_DEL it tries to delete an + /// EmojiSpan from an Editable. Returns {@code true} if an EmojiSpan is + /// deleted with the characters it covers. + ///

+ /// If there is a selection where selection start is not equal to selection end, does not + /// delete. + ///

+ /// When used on devices running API 18 or below, always returns {@code false}. + ///@param editable Editable instance passed to KeyListener\#onKeyDown(android.view.View, + /// Editable, int, KeyEvent) + ///@param keyCode keyCode passed to KeyListener\#onKeyDown(android.view.View, Editable, + /// int, KeyEvent) + ///@param event KeyEvent passed to KeyListener\#onKeyDown(android.view.View, Editable, + /// int, KeyEvent) + ///@return {@code true} if an EmojiSpan is deleted + static bool handleOnKeyDown( + jni.JObject editable, + int keyCode, + jni.JObject event, + ) { + return _handleOnKeyDown(editable.reference, keyCode, event.reference) + .boolean; + } + + static final _handleDeleteSurroundingText = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Int32, + ffi.Int32, + ffi.Uint8)>>("EmojiCompat__handleDeleteSurroundingText") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer, int, int, int)>(); + + /// from: static public boolean handleDeleteSurroundingText(android.view.inputmethod.InputConnection inputConnection, android.text.Editable editable, int beforeLength, int afterLength, boolean inCodePoints) + /// + /// Handles deleteSurroundingText commands from InputConnection and tries to delete an + /// EmojiSpan from an Editable. Returns {@code true} if an EmojiSpan is + /// deleted. + ///

+ /// If there is a selection where selection start is not equal to selection end, does not + /// delete. + ///

+ /// When used on devices running API 18 or below, always returns {@code false}. + ///@param inputConnection InputConnection instance + ///@param editable TextView.Editable instance + ///@param beforeLength the number of characters before the cursor to be deleted + ///@param afterLength the number of characters after the cursor to be deleted + ///@param inCodePoints {@code true} if length parameters are in codepoints + ///@return {@code true} if an EmojiSpan is deleted + static bool handleDeleteSurroundingText( + jni.JObject inputConnection, + jni.JObject editable, + int beforeLength, + int afterLength, + bool inCodePoints, + ) { + return _handleDeleteSurroundingText(inputConnection.reference, + editable.reference, beforeLength, afterLength, inCodePoints ? 1 : 0) + .boolean; + } + + static final _hasEmojiGlyph = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("EmojiCompat__hasEmojiGlyph") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public boolean hasEmojiGlyph(java.lang.CharSequence sequence) + /// + /// Returns {@code true} if EmojiCompat is capable of rendering an emoji. When used on devices + /// running API 18 or below, always returns {@code false}. + ///@deprecated use getEmojiMatch which returns more accurate lookup information. + ///@param sequence CharSequence representing the emoji + ///@return {@code true} if EmojiCompat can render given emoji, cannot be {@code null} + ///@throws IllegalStateException if not initialized yet + bool hasEmojiGlyph( + jni.JObject sequence, + ) { + return _hasEmojiGlyph(reference, sequence.reference).boolean; + } + + static final _hasEmojiGlyph1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Int32)>>("EmojiCompat__hasEmojiGlyph1") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer, int)>(); + + /// from: public boolean hasEmojiGlyph(java.lang.CharSequence sequence, int metadataVersion) + /// + /// Returns {@code true} if EmojiCompat is capable of rendering an emoji at the given metadata + /// version. When used on devices running API 18 or below, always returns {@code false}. + ///@deprecated use getEmojiMatch which returns more accurate lookup information. + ///@param sequence CharSequence representing the emoji + ///@param metadataVersion the metadata version to check against, should be greater than or + /// equal to {@code 0}, + ///@return {@code true} if EmojiCompat can render given emoji, cannot be {@code null} + ///@throws IllegalStateException if not initialized yet + bool hasEmojiGlyph1( + jni.JObject sequence, + int metadataVersion, + ) { + return _hasEmojiGlyph1(reference, sequence.reference, metadataVersion) + .boolean; + } + + static final _getEmojiMatch = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Int32)>>("EmojiCompat__getEmojiMatch") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer, int)>(); + + /// from: public int getEmojiMatch(java.lang.CharSequence sequence, int metadataVersion) + /// + /// Attempts to lookup the entire sequence at the specified metadata version and returns what + /// the runtime match behavior would be. + /// + /// To be used by keyboards to show or hide emoji in response to specific metadata support. + ///@see \#EMOJI_SUPPORTED + ///@see \#EMOJI_UNSUPPORTED + ///@see \#EMOJI_FALLBACK + ///@param sequence CharSequence representing an emoji + ///@param metadataVersion the metada version to check against, should be greater than or + /// equal to {@code 0}, + ///@return A match result, or decomposes if replaceAll would cause partial subsequence matches. + int getEmojiMatch( + jni.JObject sequence, + int metadataVersion, + ) { + return _getEmojiMatch(reference, sequence.reference, metadataVersion) + .integer; + } + + static final _process = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("EmojiCompat__process") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public java.lang.CharSequence process(java.lang.CharSequence charSequence) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Checks a given CharSequence for emojis, and adds EmojiSpans if any emojis are found. When + /// used on devices running API 18 or below, returns the given {@code charSequence} without + /// processing it. + ///@param charSequence CharSequence to add the EmojiSpans + ///@throws IllegalStateException if not initialized yet + ///@see \#process(CharSequence, int, int) + jni.JObject process( + jni.JObject charSequence, + ) { + return const jni.JObjectType() + .fromRef(_process(reference, charSequence.reference).object); + } + + static final _process1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Int32, + ffi.Int32)>>("EmojiCompat__process1") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer, int, int)>(); + + /// from: public java.lang.CharSequence process(java.lang.CharSequence charSequence, int start, int end) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Checks a given CharSequence for emojis, and adds EmojiSpans if any emojis are found. + /// + ///

    + ///
  • If no emojis are found, {@code charSequence} given as the input is returned without + /// any changes. i.e. charSequence is a String, and no emojis are found, the same String is + /// returned.
  • + ///
  • If the given input is not a Spannable (such as String), and at least one emoji is found + /// a new android.text.Spannable instance is returned.
  • + ///
  • If the given input is a Spannable, the same instance is returned.
  • + ///
+ /// When used on devices running API 18 or below, returns the given {@code charSequence} without + /// processing it. + ///@param charSequence CharSequence to add the EmojiSpans, cannot be {@code null} + ///@param start start index in the charSequence to look for emojis, should be greater than or + /// equal to {@code 0}, also less than or equal to {@code charSequence.length()} + ///@param end end index in the charSequence to look for emojis, should be greater than or equal + /// to {@code start} parameter, also less than or equal to + /// {@code charSequence.length()} + ///@throws IllegalStateException if not initialized yet + ///@throws IllegalArgumentException in the following cases: + /// {@code start < 0}, {@code end < 0}, {@code end < start}, + /// {@code start > charSequence.length()}, + /// {@code end > charSequence.length()} + jni.JObject process1( + jni.JObject charSequence, + int start, + int end, + ) { + return const jni.JObjectType().fromRef( + _process1(reference, charSequence.reference, start, end).object); + } + + static final _process2 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Int32, + ffi.Int32, + ffi.Int32)>>("EmojiCompat__process2") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer, int, int, int)>(); + + /// from: public java.lang.CharSequence process(java.lang.CharSequence charSequence, int start, int end, int maxEmojiCount) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Checks a given CharSequence for emojis, and adds EmojiSpans if any emojis are found. + /// + ///
    + ///
  • If no emojis are found, {@code charSequence} given as the input is returned without + /// any changes. i.e. charSequence is a String, and no emojis are found, the same String is + /// returned.
  • + ///
  • If the given input is not a Spannable (such as String), and at least one emoji is found + /// a new android.text.Spannable instance is returned.
  • + ///
  • If the given input is a Spannable, the same instance is returned.
  • + ///
+ /// When used on devices running API 18 or below, returns the given {@code charSequence} without + /// processing it. + ///@param charSequence CharSequence to add the EmojiSpans, cannot be {@code null} + ///@param start start index in the charSequence to look for emojis, should be greater than or + /// equal to {@code 0}, also less than or equal to {@code charSequence.length()} + ///@param end end index in the charSequence to look for emojis, should be greater than or + /// equal to {@code start} parameter, also less than or equal to + /// {@code charSequence.length()} + ///@param maxEmojiCount maximum number of emojis in the {@code charSequence}, should be greater + /// than or equal to {@code 0} + ///@throws IllegalStateException if not initialized yet + ///@throws IllegalArgumentException in the following cases: + /// {@code start < 0}, {@code end < 0}, {@code end < start}, + /// {@code start > charSequence.length()}, + /// {@code end > charSequence.length()} + /// {@code maxEmojiCount < 0} + jni.JObject process2( + jni.JObject charSequence, + int start, + int end, + int maxEmojiCount, + ) { + return const jni.JObjectType().fromRef( + _process2(reference, charSequence.reference, start, end, maxEmojiCount) + .object); + } + + static final _process3 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Int32, + ffi.Int32, + ffi.Int32, + ffi.Int32)>>("EmojiCompat__process3") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + int, int, int, int)>(); + + /// from: public java.lang.CharSequence process(java.lang.CharSequence charSequence, int start, int end, int maxEmojiCount, int replaceStrategy) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Checks a given CharSequence for emojis, and adds EmojiSpans if any emojis are found. + /// + ///
    + ///
  • If no emojis are found, {@code charSequence} given as the input is returned without + /// any changes. i.e. charSequence is a String, and no emojis are found, the same String is + /// returned.
  • + ///
  • If the given input is not a Spannable (such as String), and at least one emoji is found + /// a new android.text.Spannable instance is returned.
  • + ///
  • If the given input is a Spannable, the same instance is returned.
  • + ///
+ /// When used on devices running API 18 or below, returns the given {@code charSequence} without + /// processing it. + ///@param charSequence CharSequence to add the EmojiSpans, cannot be {@code null} + ///@param start start index in the charSequence to look for emojis, should be greater than or + /// equal to {@code 0}, also less than or equal to {@code charSequence.length()} + ///@param end end index in the charSequence to look for emojis, should be greater than or + /// equal to {@code start} parameter, also less than or equal to + /// {@code charSequence.length()} + ///@param maxEmojiCount maximum number of emojis in the {@code charSequence}, should be greater + /// than or equal to {@code 0} + ///@param replaceStrategy whether to replace all emoji with EmojiSpans, should be one of + /// \#REPLACE_STRATEGY_DEFAULT, + /// \#REPLACE_STRATEGY_NON_EXISTENT, + /// \#REPLACE_STRATEGY_ALL + ///@throws IllegalStateException if not initialized yet + ///@throws IllegalArgumentException in the following cases: + /// {@code start < 0}, {@code end < 0}, {@code end < start}, + /// {@code start > charSequence.length()}, + /// {@code end > charSequence.length()} + /// {@code maxEmojiCount < 0} + jni.JObject process3( + jni.JObject charSequence, + int start, + int end, + int maxEmojiCount, + int replaceStrategy, + ) { + return const jni.JObjectType().fromRef(_process3(reference, + charSequence.reference, start, end, maxEmojiCount, replaceStrategy) + .object); + } + + static final _getAssetSignature = jniLookup< + ffi + .NativeFunction)>>( + "EmojiCompat__getAssetSignature") + .asFunction)>(); + + /// from: public java.lang.String getAssetSignature() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Returns signature for the currently loaded emoji assets. The signature is a SHA that is + /// constructed using emoji assets. Can be used to detect if currently loaded asset is different + /// then previous executions. When used on devices running API 18 or below, returns empty string. + ///@throws IllegalStateException if not initialized yet + jni.JString getAssetSignature() { + return const jni.JStringType() + .fromRef(_getAssetSignature(reference).object); + } + + static final _updateEditorInfo = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("EmojiCompat__updateEditorInfo") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void updateEditorInfo(android.view.inputmethod.EditorInfo outAttrs) + /// + /// Updates the EditorInfo attributes in order to communicate information to Keyboards. When + /// used on devices running API 18 or below, does not update EditorInfo attributes. + /// + /// This is called from EditText integrations that use EmojiEditTextHelper. Custom + /// widgets that allow IME not subclassing EditText should call this method when creating an + /// input connection. + /// + /// When EmojiCompat is not in \#LOAD_STATE_SUCCEEDED, this method has no effect. + /// + /// Calling this method on API levels below API 19 will have no effect, as EmojiCompat may + /// never be configured. However, it is always safe to call, even on older API levels. + ///@param outAttrs EditorInfo instance passed to + /// android.widget.TextView\#onCreateInputConnection(EditorInfo) + ///@see \#EDITOR_INFO_METAVERSION_KEY + ///@see \#EDITOR_INFO_REPLACE_ALL_KEY + void updateEditorInfo( + jni.JObject outAttrs, + ) { + return _updateEditorInfo(reference, outAttrs.reference).check(); + } +} + +final class $EmojiCompatType extends jni.JObjType { + const $EmojiCompatType(); + + @override + String get signature => r"Landroidx/emoji2/text/EmojiCompat;"; + + @override + EmojiCompat fromRef(jni.JObjectPtr ref) => EmojiCompat.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($EmojiCompatType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($EmojiCompatType) && other is $EmojiCompatType; + } +} + +/// from: androidx.emoji2.text.EmojiCompat$Config +/// +/// Configuration class for EmojiCompat. Changes to the values will be ignored after +/// \#init(Config) is called. +///@see \#init(EmojiCompat.Config) +class EmojiCompat_Config extends jni.JObject { + @override + late final jni.JObjType $type = type; + + EmojiCompat_Config.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $EmojiCompat_ConfigType(); + static final _new0 = jniLookup< + ffi + .NativeFunction)>>( + "EmojiCompat_Config__new0") + .asFunction)>(); + + /// from: protected void (androidx.emoji2.text.EmojiCompat.MetadataRepoLoader metadataLoader) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Default constructor. + ///@param metadataLoader MetadataRepoLoader instance, cannot be {@code null} + factory EmojiCompat_Config( + EmojiCompat_MetadataRepoLoader metadataLoader, + ) { + return EmojiCompat_Config.fromRef(_new0(metadataLoader.reference).object); + } + + static final _registerInitCallback = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>>( + "EmojiCompat_Config__registerInitCallback") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public androidx.emoji2.text.EmojiCompat.Config registerInitCallback(androidx.emoji2.text.EmojiCompat.InitCallback initCallback) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Registers an initialization callback. + ///@param initCallback the initialization callback to register, cannot be {@code null} + ///@return EmojiCompat.Config instance + EmojiCompat_Config registerInitCallback( + EmojiCompat_InitCallback initCallback, + ) { + return const $EmojiCompat_ConfigType().fromRef( + _registerInitCallback(reference, initCallback.reference).object); + } + + static final _unregisterInitCallback = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>>( + "EmojiCompat_Config__unregisterInitCallback") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public androidx.emoji2.text.EmojiCompat.Config unregisterInitCallback(androidx.emoji2.text.EmojiCompat.InitCallback initCallback) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Unregisters a callback that was added before. + ///@param initCallback the initialization callback to be removed, cannot be {@code null} + ///@return EmojiCompat.Config instance + EmojiCompat_Config unregisterInitCallback( + EmojiCompat_InitCallback initCallback, + ) { + return const $EmojiCompat_ConfigType().fromRef( + _unregisterInitCallback(reference, initCallback.reference).object); + } + + static final _setReplaceAll = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Uint8)>>("EmojiCompat_Config__setReplaceAll") + .asFunction, int)>(); + + /// from: public androidx.emoji2.text.EmojiCompat.Config setReplaceAll(boolean replaceAll) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Determines whether EmojiCompat should replace all the emojis it finds with the + /// EmojiSpans. By default EmojiCompat tries its best to understand if the system already + /// can render an emoji and do not replace those emojis. + ///@param replaceAll replace all emojis found with EmojiSpans + ///@return EmojiCompat.Config instance + EmojiCompat_Config setReplaceAll( + bool replaceAll, + ) { + return const $EmojiCompat_ConfigType() + .fromRef(_setReplaceAll(reference, replaceAll ? 1 : 0).object); + } + + static final _setUseEmojiAsDefaultStyle = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Uint8)>>("EmojiCompat_Config__setUseEmojiAsDefaultStyle") + .asFunction, int)>(); + + /// from: public androidx.emoji2.text.EmojiCompat.Config setUseEmojiAsDefaultStyle(boolean useEmojiAsDefaultStyle) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Determines whether EmojiCompat should use the emoji presentation style for emojis + /// that have text style as default. By default, the text style would be used, unless these + /// are followed by the U+FE0F variation selector. + /// Details about emoji presentation and text presentation styles can be found here: + /// http://unicode.org/reports/tr51/\#Presentation_Style + /// If useEmojiAsDefaultStyle is true, the emoji presentation style will be used for all + /// emojis, including potentially unexpected ones (such as digits or other keycap emojis). If + /// this is not the expected behaviour, method + /// \#setUseEmojiAsDefaultStyle(boolean, List) can be used to specify the + /// exception emojis that should be still presented as text style. + ///@param useEmojiAsDefaultStyle whether to use the emoji style presentation for all emojis + /// that would be presented as text style by default + EmojiCompat_Config setUseEmojiAsDefaultStyle( + bool useEmojiAsDefaultStyle, + ) { + return const $EmojiCompat_ConfigType().fromRef( + _setUseEmojiAsDefaultStyle(reference, useEmojiAsDefaultStyle ? 1 : 0) + .object); + } + + static final _setUseEmojiAsDefaultStyle1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, ffi.Uint8, + ffi.Pointer)>>( + "EmojiCompat_Config__setUseEmojiAsDefaultStyle1") + .asFunction< + jni.JniResult Function( + ffi.Pointer, int, ffi.Pointer)>(); + + /// from: public androidx.emoji2.text.EmojiCompat.Config setUseEmojiAsDefaultStyle(boolean useEmojiAsDefaultStyle, java.util.List emojiAsDefaultStyleExceptions) + /// The returned object must be released after use, by calling the [release] method. + /// + /// @see \#setUseEmojiAsDefaultStyle(boolean) + ///@param emojiAsDefaultStyleExceptions Contains the exception emojis which will be still + /// presented as text style even if the + /// useEmojiAsDefaultStyle flag is set to {@code true}. + /// This list will be ignored if useEmojiAsDefaultStyle + /// is {@code false}. Note that emojis with default + /// emoji style presentation will remain emoji style + /// regardless the value of useEmojiAsDefaultStyle or + /// whether they are included in the exceptions list or + /// not. When no exception is wanted, the method + /// \#setUseEmojiAsDefaultStyle(boolean) should + /// be used instead. + EmojiCompat_Config setUseEmojiAsDefaultStyle1( + bool useEmojiAsDefaultStyle, + jni.JList emojiAsDefaultStyleExceptions, + ) { + return const $EmojiCompat_ConfigType().fromRef(_setUseEmojiAsDefaultStyle1( + reference, + useEmojiAsDefaultStyle ? 1 : 0, + emojiAsDefaultStyleExceptions.reference) + .object); + } + + static final _setEmojiSpanIndicatorEnabled = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, ffi.Uint8)>>( + "EmojiCompat_Config__setEmojiSpanIndicatorEnabled") + .asFunction, int)>(); + + /// from: public androidx.emoji2.text.EmojiCompat.Config setEmojiSpanIndicatorEnabled(boolean emojiSpanIndicatorEnabled) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Determines whether a background will be drawn for the emojis that are found and + /// replaced by EmojiCompat. Should be used only for debugging purposes. The indicator color + /// can be set using \#setEmojiSpanIndicatorColor(int). + ///@param emojiSpanIndicatorEnabled when {@code true} a background is drawn for each emoji + /// that is replaced + EmojiCompat_Config setEmojiSpanIndicatorEnabled( + bool emojiSpanIndicatorEnabled, + ) { + return const $EmojiCompat_ConfigType().fromRef( + _setEmojiSpanIndicatorEnabled( + reference, emojiSpanIndicatorEnabled ? 1 : 0) + .object); + } + + static final _setEmojiSpanIndicatorColor = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Int32)>>("EmojiCompat_Config__setEmojiSpanIndicatorColor") + .asFunction, int)>(); + + /// from: public androidx.emoji2.text.EmojiCompat.Config setEmojiSpanIndicatorColor(int color) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Sets the color used as emoji span indicator. The default value is + /// Color\#GREEN Color.GREEN. + ///@see \#setEmojiSpanIndicatorEnabled(boolean) + EmojiCompat_Config setEmojiSpanIndicatorColor( + int color, + ) { + return const $EmojiCompat_ConfigType() + .fromRef(_setEmojiSpanIndicatorColor(reference, color).object); + } + + static final _setMetadataLoadStrategy = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Int32)>>("EmojiCompat_Config__setMetadataLoadStrategy") + .asFunction, int)>(); + + /// from: public androidx.emoji2.text.EmojiCompat.Config setMetadataLoadStrategy(int strategy) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Determines the strategy to start loading the metadata. By default EmojiCompat + /// will start loading the metadata during EmojiCompat\#init(Config). When set to + /// EmojiCompat\#LOAD_STRATEGY_MANUAL, you should call EmojiCompat\#load() to + /// initiate metadata loading. + ///

+ /// Default implementations of EmojiCompat.MetadataRepoLoader start a thread + /// during their EmojiCompat.MetadataRepoLoader\#load functions. Just instantiating + /// and starting a thread might take time especially in older devices. Since + /// EmojiCompat\#init(Config) has to be called before any EmojiCompat widgets are + /// inflated, this results in time spent either on your Application.onCreate or Activity + /// .onCreate. If you'd like to gain more control on when to start loading the metadata + /// and be able to call EmojiCompat\#init(Config) with absolute minimum time cost you + /// can use EmojiCompat\#LOAD_STRATEGY_MANUAL. + ///

+ /// When set to EmojiCompat\#LOAD_STRATEGY_MANUAL, EmojiCompat will wait + /// for \#load() to be called by the developer in order to start loading metadata, + /// therefore you should call EmojiCompat\#load() to initiate metadata loading. + /// \#load() can be called from any thread. + ///

+  /// EmojiCompat.Config config = new FontRequestEmojiCompatConfig(context, fontRequest)
+  ///         .setMetadataLoadStrategy(EmojiCompat.LOAD_STRATEGY_MANUAL);
+  ///
+  /// // EmojiCompat will not start loading metadata and MetadataRepoLoader\#load(...)
+  /// // will not be called
+  /// EmojiCompat.init(config);
+  ///
+  /// // At any time (i.e. idle time or executorService is ready)
+  /// // call EmojiCompat\#load() to start loading metadata.
+  /// executorService.execute(() -> EmojiCompat.get().load());
+  /// 
+ ///@param strategy one of EmojiCompat\#LOAD_STRATEGY_DEFAULT, + /// EmojiCompat\#LOAD_STRATEGY_MANUAL + EmojiCompat_Config setMetadataLoadStrategy( + int strategy, + ) { + return const $EmojiCompat_ConfigType() + .fromRef(_setMetadataLoadStrategy(reference, strategy).object); + } + + static final _setSpanFactory = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("EmojiCompat_Config__setSpanFactory") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public androidx.emoji2.text.EmojiCompat.Config setSpanFactory(androidx.emoji2.text.EmojiCompat.SpanFactory factory) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Set the span factory used to actually draw emoji replacements. + ///@param factory custum span factory that can draw the emoji replacements + ///@return this + EmojiCompat_Config setSpanFactory( + EmojiCompat_SpanFactory factory0, + ) { + return const $EmojiCompat_ConfigType() + .fromRef(_setSpanFactory(reference, factory0.reference).object); + } + + static final _setGlyphChecker = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>>( + "EmojiCompat_Config__setGlyphChecker") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public androidx.emoji2.text.EmojiCompat.Config setGlyphChecker(androidx.emoji2.text.EmojiCompat.GlyphChecker glyphChecker) + /// The returned object must be released after use, by calling the [release] method. + /// + /// The interface that is used by EmojiCompat in order to check if a given emoji can be + /// rendered by the system. + ///@param glyphChecker GlyphChecker instance to be used. + EmojiCompat_Config setGlyphChecker( + EmojiCompat_GlyphChecker glyphChecker, + ) { + return const $EmojiCompat_ConfigType() + .fromRef(_setGlyphChecker(reference, glyphChecker.reference).object); + } + + static final _getMetadataRepoLoader = jniLookup< + ffi + .NativeFunction)>>( + "EmojiCompat_Config__getMetadataRepoLoader") + .asFunction)>(); + + /// from: protected final androidx.emoji2.text.EmojiCompat.MetadataRepoLoader getMetadataRepoLoader() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Returns the MetadataRepoLoader. + EmojiCompat_MetadataRepoLoader getMetadataRepoLoader() { + return const $EmojiCompat_MetadataRepoLoaderType() + .fromRef(_getMetadataRepoLoader(reference).object); + } +} + +final class $EmojiCompat_ConfigType extends jni.JObjType { + const $EmojiCompat_ConfigType(); + + @override + String get signature => r"Landroidx/emoji2/text/EmojiCompat$Config;"; + + @override + EmojiCompat_Config fromRef(jni.JObjectPtr ref) => + EmojiCompat_Config.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($EmojiCompat_ConfigType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($EmojiCompat_ConfigType) && + other is $EmojiCompat_ConfigType; + } +} + +/// from: androidx.emoji2.text.EmojiCompat$MetadataRepoLoaderCallback +/// +/// Callback to inform EmojiCompat about the state of the metadata load. Passed to +/// MetadataRepoLoader during MetadataRepoLoader\#load(MetadataRepoLoaderCallback) call. +class EmojiCompat_MetadataRepoLoaderCallback extends jni.JObject { + @override + late final jni.JObjType $type = type; + + EmojiCompat_MetadataRepoLoaderCallback.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $EmojiCompat_MetadataRepoLoaderCallbackType(); + static final _new0 = jniLookup>( + "EmojiCompat_MetadataRepoLoaderCallback__new0") + .asFunction(); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory EmojiCompat_MetadataRepoLoaderCallback() { + return EmojiCompat_MetadataRepoLoaderCallback.fromRef(_new0().object); + } + + static final _onLoaded = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>>( + "EmojiCompat_MetadataRepoLoaderCallback__onLoaded") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public abstract void onLoaded(androidx.emoji2.text.MetadataRepo metadataRepo) + /// + /// Called by MetadataRepoLoader when metadata is loaded successfully. + ///@param metadataRepo MetadataRepo instance, cannot be {@code null} + void onLoaded( + jni.JObject metadataRepo, + ) { + return _onLoaded(reference, metadataRepo.reference).check(); + } + + static final _onFailed = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>>( + "EmojiCompat_MetadataRepoLoaderCallback__onFailed") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public abstract void onFailed(java.lang.Throwable throwable) + /// + /// Called by MetadataRepoLoader if an error occurs while loading the metadata. + ///@param throwable the exception that caused the failure, {@code nullable} + void onFailed( + jni.JObject throwable, + ) { + return _onFailed(reference, throwable.reference).check(); + } +} + +final class $EmojiCompat_MetadataRepoLoaderCallbackType + extends jni.JObjType { + const $EmojiCompat_MetadataRepoLoaderCallbackType(); + + @override + String get signature => + r"Landroidx/emoji2/text/EmojiCompat$MetadataRepoLoaderCallback;"; + + @override + EmojiCompat_MetadataRepoLoaderCallback fromRef(jni.JObjectPtr ref) => + EmojiCompat_MetadataRepoLoaderCallback.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($EmojiCompat_MetadataRepoLoaderCallbackType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($EmojiCompat_MetadataRepoLoaderCallbackType) && + other is $EmojiCompat_MetadataRepoLoaderCallbackType; + } +} + +/// from: androidx.emoji2.text.EmojiCompat$GlyphChecker +/// +/// Interface to check if a given emoji exists on the system. +class EmojiCompat_GlyphChecker extends jni.JObject { + @override + late final jni.JObjType $type = type; + + EmojiCompat_GlyphChecker.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $EmojiCompat_GlyphCheckerType(); + static final _hasGlyph = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Int32, + ffi.Int32, + ffi.Int32)>>("EmojiCompat_GlyphChecker__hasGlyph") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer, int, int, int)>(); + + /// from: public abstract boolean hasGlyph(java.lang.CharSequence charSequence, int start, int end, int sdkAdded) + /// + /// Return {@code true} if the emoji that is in {@code charSequence} between + /// {@code start}(inclusive) and {@code end}(exclusive) can be rendered on the system + /// using the default Typeface. + /// + /// This function is called after an emoji is identified in the given {@code charSequence} + /// and EmojiCompat wants to know if that emoji can be rendered on the system. The result + /// of this call will be cached and the same emoji sequence won't be asked for the same + /// EmojiCompat instance. + /// + /// When the function returns {@code true}, it will mean that the system can render the + /// emoji. In that case if Config\#setReplaceAll is set to {@code false}, then no + /// EmojiSpan will be added in the final emoji processing result. + /// + /// When the function returns {@code false}, it will mean that the system cannot render + /// the given emoji, therefore an EmojiSpan will be added to the final emoji + /// processing result. + /// + /// The default implementation of this class uses + /// androidx.core.graphics.PaintCompat\#hasGlyph(Paint, String) function to check + /// if the emoji can be rendered on the system. This is required even if EmojiCompat + /// knows about the SDK Version that the emoji was added on AOSP. Just the {@code sdkAdded} + /// information is not enough to reliably decide if emoji can be rendered since this + /// information may not be consistent across all the OEMs and all the Android versions. + /// + /// With this interface you can apply your own heuristics to check if the emoji can be + /// rendered on the system. For example, if you'd like to rely on the {@code sdkAdded} + /// information, and some predefined OEMs, it is possible to write the following code + /// snippet. + /// + /// {@sample frameworks/support/samples/SupportEmojiDemos/src/main/java/com/example/android/support/text/emoji/sample/GlyphCheckerSample.java glyphchecker} + ///@param charSequence the CharSequence that is being processed + ///@param start the inclusive starting offset for the emoji in the {@code charSequence} + ///@param end the exclusive end offset for the emoji in the {@code charSequence} + ///@param sdkAdded the API version that the emoji was added in AOSP + ///@return true if the given sequence can be rendered as a single glyph, otherwise false. + bool hasGlyph( + jni.JObject charSequence, + int start, + int end, + int sdkAdded, + ) { + return _hasGlyph(reference, charSequence.reference, start, end, sdkAdded) + .boolean; + } +} + +final class $EmojiCompat_GlyphCheckerType + extends jni.JObjType { + const $EmojiCompat_GlyphCheckerType(); + + @override + String get signature => r"Landroidx/emoji2/text/EmojiCompat$GlyphChecker;"; + + @override + EmojiCompat_GlyphChecker fromRef(jni.JObjectPtr ref) => + EmojiCompat_GlyphChecker.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($EmojiCompat_GlyphCheckerType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($EmojiCompat_GlyphCheckerType) && + other is $EmojiCompat_GlyphCheckerType; + } +} + +/// from: androidx.emoji2.text.EmojiCompat$MetadataRepoLoader +/// +/// Interface to load emoji metadata. +class EmojiCompat_MetadataRepoLoader extends jni.JObject { + @override + late final jni.JObjType $type = type; + + EmojiCompat_MetadataRepoLoader.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $EmojiCompat_MetadataRepoLoaderType(); + static final _load = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>>( + "EmojiCompat_MetadataRepoLoader__load") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public abstract void load(androidx.emoji2.text.EmojiCompat.MetadataRepoLoaderCallback loaderCallback) + /// + /// Start loading the metadata. When the loading operation is finished MetadataRepoLoaderCallback\#onLoaded(MetadataRepo) or + /// MetadataRepoLoaderCallback\#onFailed(Throwable) should be called. When used on + /// devices running API 18 or below, this function is never called. + ///@param loaderCallback callback to signal the loading state + void load( + EmojiCompat_MetadataRepoLoaderCallback loaderCallback, + ) { + return _load(reference, loaderCallback.reference).check(); + } +} + +final class $EmojiCompat_MetadataRepoLoaderType + extends jni.JObjType { + const $EmojiCompat_MetadataRepoLoaderType(); + + @override + String get signature => + r"Landroidx/emoji2/text/EmojiCompat$MetadataRepoLoader;"; + + @override + EmojiCompat_MetadataRepoLoader fromRef(jni.JObjectPtr ref) => + EmojiCompat_MetadataRepoLoader.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($EmojiCompat_MetadataRepoLoaderType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($EmojiCompat_MetadataRepoLoaderType) && + other is $EmojiCompat_MetadataRepoLoaderType; + } +} + +/// from: androidx.emoji2.text.EmojiCompat$InitCallback +/// +/// Listener class for the initialization of the EmojiCompat. +class EmojiCompat_InitCallback extends jni.JObject { + @override + late final jni.JObjType $type = type; + + EmojiCompat_InitCallback.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $EmojiCompat_InitCallbackType(); + static final _new0 = jniLookup>( + "EmojiCompat_InitCallback__new0") + .asFunction(); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory EmojiCompat_InitCallback() { + return EmojiCompat_InitCallback.fromRef(_new0().object); + } + + static final _onInitialized = jniLookup< + ffi + .NativeFunction)>>( + "EmojiCompat_InitCallback__onInitialized") + .asFunction)>(); + + /// from: public void onInitialized() + /// + /// Called when EmojiCompat is initialized and the emoji data is loaded. When used on devices + /// running API 18 or below, this function is always called. + void onInitialized() { + return _onInitialized(reference).check(); + } + + static final _onFailed = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("EmojiCompat_InitCallback__onFailed") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void onFailed(java.lang.Throwable throwable) + /// + /// Called when an unrecoverable error occurs during EmojiCompat initialization. When used on + /// devices running API 18 or below, this function is never called. + void onFailed( + jni.JObject throwable, + ) { + return _onFailed(reference, throwable.reference).check(); + } +} + +final class $EmojiCompat_InitCallbackType + extends jni.JObjType { + const $EmojiCompat_InitCallbackType(); + + @override + String get signature => r"Landroidx/emoji2/text/EmojiCompat$InitCallback;"; + + @override + EmojiCompat_InitCallback fromRef(jni.JObjectPtr ref) => + EmojiCompat_InitCallback.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($EmojiCompat_InitCallbackType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($EmojiCompat_InitCallbackType) && + other is $EmojiCompat_InitCallbackType; + } +} + +/// from: androidx.emoji2.text.EmojiCompat$DefaultSpanFactory +/// +/// @hide +class EmojiCompat_DefaultSpanFactory extends jni.JObject { + @override + late final jni.JObjType $type = type; + + EmojiCompat_DefaultSpanFactory.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $EmojiCompat_DefaultSpanFactoryType(); + static final _new0 = jniLookup>( + "EmojiCompat_DefaultSpanFactory__new0") + .asFunction(); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory EmojiCompat_DefaultSpanFactory() { + return EmojiCompat_DefaultSpanFactory.fromRef(_new0().object); + } + + static final _createSpan = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>>( + "EmojiCompat_DefaultSpanFactory__createSpan") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public androidx.emoji2.text.EmojiSpan createSpan(androidx.emoji2.text.TypefaceEmojiRasterizer rasterizer) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Returns a TypefaceEmojiSpan. + ///@param rasterizer TypefaceEmojiRasterizer instance, which can draw the emoji onto a + /// Canvas. + ///@return TypefaceEmojiSpan + jni.JObject createSpan( + jni.JObject rasterizer, + ) { + return const jni.JObjectType() + .fromRef(_createSpan(reference, rasterizer.reference).object); + } +} + +final class $EmojiCompat_DefaultSpanFactoryType + extends jni.JObjType { + const $EmojiCompat_DefaultSpanFactoryType(); + + @override + String get signature => + r"Landroidx/emoji2/text/EmojiCompat$DefaultSpanFactory;"; + + @override + EmojiCompat_DefaultSpanFactory fromRef(jni.JObjectPtr ref) => + EmojiCompat_DefaultSpanFactory.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($EmojiCompat_DefaultSpanFactoryType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($EmojiCompat_DefaultSpanFactoryType) && + other is $EmojiCompat_DefaultSpanFactoryType; + } +} + +/// from: androidx.emoji2.text.EmojiCompat$SpanFactory +/// +/// Factory class that creates the EmojiSpans. +/// +/// By default it creates TypefaceEmojiSpan. +/// +/// Apps should use this only if they want to control the drawing of EmojiSpans for non-standard +/// emoji display (for example, resizing or repositioning emoji). +class EmojiCompat_SpanFactory extends jni.JObject { + @override + late final jni.JObjType $type = type; + + EmojiCompat_SpanFactory.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $EmojiCompat_SpanFactoryType(); + static final _createSpan = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>>( + "EmojiCompat_SpanFactory__createSpan") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public abstract androidx.emoji2.text.EmojiSpan createSpan(androidx.emoji2.text.TypefaceEmojiRasterizer rasterizer) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Create EmojiSpan instance. + ///@param rasterizer TypefaceEmojiRasterizer instance, which can draw the emoji onto a + /// Canvas. + ///@return EmojiSpan instance that can use TypefaceEmojiRasterizer to draw emoji. + jni.JObject createSpan( + jni.JObject rasterizer, + ) { + return const jni.JObjectType() + .fromRef(_createSpan(reference, rasterizer.reference).object); + } +} + +final class $EmojiCompat_SpanFactoryType + extends jni.JObjType { + const $EmojiCompat_SpanFactoryType(); + + @override + String get signature => r"Landroidx/emoji2/text/EmojiCompat$SpanFactory;"; + + @override + EmojiCompat_SpanFactory fromRef(jni.JObjectPtr ref) => + EmojiCompat_SpanFactory.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($EmojiCompat_SpanFactoryType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($EmojiCompat_SpanFactoryType) && + other is $EmojiCompat_SpanFactoryType; + } +} + +/// from: androidx.emoji2.text.DefaultEmojiCompatConfig +/// +/// The default config will use downloadable fonts to fetch the emoji compat font file. +/// +/// It will automatically fetch the emoji compat font from a {@code ContentProvider} that is +/// installed on the devices system image, if present. +/// +/// +/// You should use this if you want the default emoji font from a system installed +/// downloadable fonts provider. This is the recommended behavior for all applications unless +/// they install a custom emoji font. +/// +/// +/// You may need to specialize the configuration beyond this default config in some +/// situations: +/// +///
    +///
  • If you are trying to install a custom emoji font through downloadable fonts use +/// FontRequestEmojiCompatConfig instead of this method.
  • +///
  • If you're trying to bundle an emoji font with your APK use {@code +/// BundledEmojiCompatConfig} in the {@code emoji2-bundled} artifact.
  • +///
  • If you are building an APK that will be installed on devices that won't have a +/// downloadable fonts provider, use {@code BundledEmojiCompatConfig}.
  • +///
+/// +/// The downloadable font provider used by {@code DefaultEmojiCompatConfig} always satisfies +/// the following contract: +/// +///
    +///
  1. It MUST provide an intent filter for {@code androidx.content.action.LOAD_EMOJI_FONT}. +///
  2. +///
  3. It MUST respond to the query {@code emojicompat-emoji-font} with a valid emoji compat +/// font file including metadata.
  4. +///
  5. It MUST provide fonts via the same contract as downloadable fonts.
  6. +///
  7. It MUST be installed in the system image.
  8. +///
+class DefaultEmojiCompatConfig extends jni.JObject { + @override + late final jni.JObjType $type = type; + + DefaultEmojiCompatConfig.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $DefaultEmojiCompatConfigType(); + static final _create = jniLookup< + ffi + .NativeFunction)>>( + "DefaultEmojiCompatConfig__create") + .asFunction)>(); + + /// from: static public androidx.emoji2.text.FontRequestEmojiCompatConfig create(android.content.Context context) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Get the default emoji compat config for this device. + /// + /// You may further configure the returned config before passing it to EmojiCompat\#init. + /// + /// Each call to this method will return a new EmojiCompat.Config, so changes to the returned + /// object will not modify future return values. + ///@param context context for lookup + ///@return A valid config for downloading the emoji compat font, or null if no font provider + /// could be found. + static jni.JObject create( + jni.JObject context, + ) { + return const jni.JObjectType().fromRef(_create(context.reference).object); + } +} + +final class $DefaultEmojiCompatConfigType + extends jni.JObjType { + const $DefaultEmojiCompatConfigType(); + + @override + String get signature => r"Landroidx/emoji2/text/DefaultEmojiCompatConfig;"; + + @override + DefaultEmojiCompatConfig fromRef(jni.JObjectPtr ref) => + DefaultEmojiCompatConfig.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($DefaultEmojiCompatConfigType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($DefaultEmojiCompatConfigType) && + other is $DefaultEmojiCompatConfigType; + } +} + +/// from: androidx.emoji2.text.DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper_API28 +/// +/// Helper to lookup signatures in package manager > API 28 +///@hide +class DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28 + extends DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19 { + @override + late final jni + .JObjType + $type = type; + + DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = + $DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28Type(); + static final _new0 = jniLookup>( + "DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28__new0") + .asFunction(); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28() { + return DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28 + .fromRef(_new0().object); + } + + static final _getSigningSignatures1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer, ffi.Pointer)>>( + "DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28__getSigningSignatures1") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); + + /// from: public android.content.pm.Signature[] getSigningSignatures(android.content.pm.PackageManager packageManager, java.lang.String providerPackage) + /// The returned object must be released after use, by calling the [release] method. + jni.JArray getSigningSignatures1( + jni.JObject packageManager, + jni.JString providerPackage, + ) { + return const jni.JArrayType(jni.JObjectType()).fromRef( + _getSigningSignatures1( + reference, packageManager.reference, providerPackage.reference) + .object); + } +} + +final class $DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28Type + extends jni + .JObjType { + const $DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28Type(); + + @override + String get signature => + r"Landroidx/emoji2/text/DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper_API28;"; + + @override + DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28 fromRef( + jni.JObjectPtr ref) => + DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28.fromRef( + ref); + + @override + jni.JObjType get superType => + const $DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19Type(); + + @override + final superCount = 3; + + @override + int get hashCode => + ($DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28Type) + .hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == + ($DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28Type) && + other + is $DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28Type; + } +} + +/// from: androidx.emoji2.text.DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper_API19 +/// +/// Actually do lookups > API 19 +///@hide +class DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19 + extends DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper { + @override + late final jni + .JObjType + $type = type; + + DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = + $DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19Type(); + static final _new0 = jniLookup>( + "DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19__new0") + .asFunction(); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19() { + return DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19 + .fromRef(_new0().object); + } + + static final _queryIntentContentProviders = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Int32)>>( + "DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19__queryIntentContentProviders") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer, int)>(); + + /// from: public java.util.List queryIntentContentProviders(android.content.pm.PackageManager packageManager, android.content.Intent intent, int flags) + /// The returned object must be released after use, by calling the [release] method. + jni.JList queryIntentContentProviders( + jni.JObject packageManager, + jni.JObject intent, + int flags, + ) { + return const jni.JListType(jni.JObjectType()).fromRef( + _queryIntentContentProviders( + reference, packageManager.reference, intent.reference, flags) + .object); + } + + static final _getProviderInfo = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>>( + "DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19__getProviderInfo") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public android.content.pm.ProviderInfo getProviderInfo(android.content.pm.ResolveInfo resolveInfo) + /// The returned object must be released after use, by calling the [release] method. + jni.JObject getProviderInfo( + jni.JObject resolveInfo, + ) { + return const jni.JObjectType() + .fromRef(_getProviderInfo(reference, resolveInfo.reference).object); + } +} + +final class $DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19Type + extends jni + .JObjType { + const $DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19Type(); + + @override + String get signature => + r"Landroidx/emoji2/text/DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper_API19;"; + + @override + DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19 fromRef( + jni.JObjectPtr ref) => + DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19.fromRef( + ref); + + @override + jni.JObjType get superType => + const $DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelperType(); + + @override + final superCount = 2; + + @override + int get hashCode => + ($DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19Type) + .hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == + ($DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19Type) && + other + is $DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19Type; + } +} + +/// from: androidx.emoji2.text.DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper +/// +/// Helper to lookup signatures in package manager. +///@hide +class DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper + extends jni.JObject { + @override + late final jni + .JObjType $type = + type; + + DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = + $DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelperType(); + static final _new0 = jniLookup>( + "DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__new0") + .asFunction(); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper() { + return DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper.fromRef( + _new0().object); + } + + static final _getSigningSignatures = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer, ffi.Pointer)>>( + "DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__getSigningSignatures") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); + + /// from: public android.content.pm.Signature[] getSigningSignatures(android.content.pm.PackageManager packageManager, java.lang.String providerPackage) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Get the signing signatures for a package in package manager. + jni.JArray getSigningSignatures( + jni.JObject packageManager, + jni.JString providerPackage, + ) { + return const jni.JArrayType(jni.JObjectType()).fromRef( + _getSigningSignatures( + reference, packageManager.reference, providerPackage.reference) + .object); + } + + static final _queryIntentContentProviders = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Int32)>>( + "DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__queryIntentContentProviders") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer, int)>(); + + /// from: public java.util.List queryIntentContentProviders(android.content.pm.PackageManager packageManager, android.content.Intent intent, int flags) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Get the content provider by intent. + jni.JList queryIntentContentProviders( + jni.JObject packageManager, + jni.JObject intent, + int flags, + ) { + return const jni.JListType(jni.JObjectType()).fromRef( + _queryIntentContentProviders( + reference, packageManager.reference, intent.reference, flags) + .object); + } + + static final _getProviderInfo = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>>( + "DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__getProviderInfo") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public android.content.pm.ProviderInfo getProviderInfo(android.content.pm.ResolveInfo resolveInfo) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Get a ProviderInfo, if present, from a ResolveInfo + ///@param resolveInfo the subject + ///@return resolveInfo.providerInfo above API 19 + jni.JObject getProviderInfo( + jni.JObject resolveInfo, + ) { + return const jni.JObjectType() + .fromRef(_getProviderInfo(reference, resolveInfo.reference).object); + } +} + +final class $DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelperType + extends jni + .JObjType { + const $DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelperType(); + + @override + String get signature => + r"Landroidx/emoji2/text/DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper;"; + + @override + DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper fromRef( + jni.JObjectPtr ref) => + DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => + ($DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelperType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == + ($DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelperType) && + other is $DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelperType; + } +} + +/// from: androidx.emoji2.text.DefaultEmojiCompatConfig$DefaultEmojiCompatConfigFactory +/// +/// Actual factory for generating default emoji configs, does service locator lookup internally. +///@see DefaultEmojiCompatConfig\#create +///@hide +class DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory + extends jni.JObject { + @override + late final jni + .JObjType + $type = type; + + DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = + $DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactoryType(); + static final _new0 = jniLookup< + ffi + .NativeFunction)>>( + "DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory__new0") + .asFunction)>(); + + /// from: public void (androidx.emoji2.text.DefaultEmojiCompatConfig.DefaultEmojiCompatConfigHelper helper) + /// The returned object must be released after use, by calling the [release] method. + /// + /// @hide + factory DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory( + DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper helper, + ) { + return DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory.fromRef( + _new0(helper.reference).object); + } + + static final _create = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>>( + "DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory__create") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public androidx.emoji2.text.EmojiCompat.Config create(android.content.Context context) + /// The returned object must be released after use, by calling the [release] method. + /// + /// @see DefaultEmojiCompatConfig\#create + ///@hide + EmojiCompat_Config create( + jni.JObject context, + ) { + return const $EmojiCompat_ConfigType() + .fromRef(_create(reference, context.reference).object); + } +} + +final class $DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactoryType + extends jni + .JObjType { + const $DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactoryType(); + + @override + String get signature => + r"Landroidx/emoji2/text/DefaultEmojiCompatConfig$DefaultEmojiCompatConfigFactory;"; + + @override + DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory fromRef( + jni.JObjectPtr ref) => + DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => + ($DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactoryType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == + ($DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactoryType) && + other is $DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactoryType; + } +} + +/// from: android.os.Build$Partition +class Build_Partition extends jni.JObject { + @override + late final jni.JObjType $type = type; + + Build_Partition.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $Build_PartitionType(); + + /// from: static public final java.lang.String PARTITION_NAME_SYSTEM + static const PARTITION_NAME_SYSTEM = r"""system"""; + + static final _getName = jniLookup< + ffi + .NativeFunction)>>( + "Build_Partition__getName") + .asFunction)>(); + + /// from: public java.lang.String getName() + /// The returned object must be released after use, by calling the [release] method. + jni.JString getName() { + return const jni.JStringType().fromRef(_getName(reference).object); + } + + static final _getFingerprint = jniLookup< + ffi + .NativeFunction)>>( + "Build_Partition__getFingerprint") + .asFunction)>(); + + /// from: public java.lang.String getFingerprint() + /// The returned object must be released after use, by calling the [release] method. + jni.JString getFingerprint() { + return const jni.JStringType().fromRef(_getFingerprint(reference).object); + } + + static final _getBuildTimeMillis = jniLookup< + ffi + .NativeFunction)>>( + "Build_Partition__getBuildTimeMillis") + .asFunction)>(); + + /// from: public long getBuildTimeMillis() + int getBuildTimeMillis() { + return _getBuildTimeMillis(reference).long; + } + + static final _equals1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("Build_Partition__equals1") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public boolean equals(java.lang.Object object) + bool equals1( + jni.JObject object, + ) { + return _equals1(reference, object.reference).boolean; + } + + static final _hashCode1 = jniLookup< + ffi + .NativeFunction)>>( + "Build_Partition__hashCode1") + .asFunction)>(); + + /// from: public int hashCode() + int hashCode1() { + return _hashCode1(reference).integer; + } +} + +final class $Build_PartitionType extends jni.JObjType { + const $Build_PartitionType(); + + @override + String get signature => r"Landroid/os/Build$Partition;"; + + @override + Build_Partition fromRef(jni.JObjectPtr ref) => Build_Partition.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($Build_PartitionType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($Build_PartitionType) && + other is $Build_PartitionType; + } +} + +/// from: android.os.Build$VERSION +class Build_VERSION extends jni.JObject { + @override + late final jni.JObjType $type = type; + + Build_VERSION.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $Build_VERSIONType(); + static final _get_BASE_OS = + jniLookup>( + "get_Build_VERSION__BASE_OS") + .asFunction(); + + /// from: static public final java.lang.String BASE_OS + /// The returned object must be released after use, by calling the [release] method. + static jni.JString get BASE_OS => + const jni.JStringType().fromRef(_get_BASE_OS().object); + + static final _get_CODENAME = + jniLookup>( + "get_Build_VERSION__CODENAME") + .asFunction(); + + /// from: static public final java.lang.String CODENAME + /// The returned object must be released after use, by calling the [release] method. + static jni.JString get CODENAME => + const jni.JStringType().fromRef(_get_CODENAME().object); + + static final _get_INCREMENTAL = + jniLookup>( + "get_Build_VERSION__INCREMENTAL") + .asFunction(); + + /// from: static public final java.lang.String INCREMENTAL + /// The returned object must be released after use, by calling the [release] method. + static jni.JString get INCREMENTAL => + const jni.JStringType().fromRef(_get_INCREMENTAL().object); + + static final _get_MEDIA_PERFORMANCE_CLASS = + jniLookup>( + "get_Build_VERSION__MEDIA_PERFORMANCE_CLASS") + .asFunction(); + + /// from: static public final int MEDIA_PERFORMANCE_CLASS + static int get MEDIA_PERFORMANCE_CLASS => + _get_MEDIA_PERFORMANCE_CLASS().integer; + + static final _get_PREVIEW_SDK_INT = + jniLookup>( + "get_Build_VERSION__PREVIEW_SDK_INT") + .asFunction(); + + /// from: static public final int PREVIEW_SDK_INT + static int get PREVIEW_SDK_INT => _get_PREVIEW_SDK_INT().integer; + + static final _get_RELEASE = + jniLookup>( + "get_Build_VERSION__RELEASE") + .asFunction(); + + /// from: static public final java.lang.String RELEASE + /// The returned object must be released after use, by calling the [release] method. + static jni.JString get RELEASE => + const jni.JStringType().fromRef(_get_RELEASE().object); + + static final _get_RELEASE_OR_CODENAME = + jniLookup>( + "get_Build_VERSION__RELEASE_OR_CODENAME") + .asFunction(); + + /// from: static public final java.lang.String RELEASE_OR_CODENAME + /// The returned object must be released after use, by calling the [release] method. + static jni.JString get RELEASE_OR_CODENAME => + const jni.JStringType().fromRef(_get_RELEASE_OR_CODENAME().object); + + static final _get_RELEASE_OR_PREVIEW_DISPLAY = + jniLookup>( + "get_Build_VERSION__RELEASE_OR_PREVIEW_DISPLAY") + .asFunction(); + + /// from: static public final java.lang.String RELEASE_OR_PREVIEW_DISPLAY + /// The returned object must be released after use, by calling the [release] method. + static jni.JString get RELEASE_OR_PREVIEW_DISPLAY => + const jni.JStringType().fromRef(_get_RELEASE_OR_PREVIEW_DISPLAY().object); + + static final _get_SDK = + jniLookup>( + "get_Build_VERSION__SDK") + .asFunction(); + + /// from: static public final java.lang.String SDK + /// The returned object must be released after use, by calling the [release] method. + static jni.JString get SDK => + const jni.JStringType().fromRef(_get_SDK().object); + + static final _get_SDK_INT = + jniLookup>( + "get_Build_VERSION__SDK_INT") + .asFunction(); + + /// from: static public final int SDK_INT + static int get SDK_INT => _get_SDK_INT().integer; + + static final _get_SECURITY_PATCH = + jniLookup>( + "get_Build_VERSION__SECURITY_PATCH") + .asFunction(); + + /// from: static public final java.lang.String SECURITY_PATCH + /// The returned object must be released after use, by calling the [release] method. + static jni.JString get SECURITY_PATCH => + const jni.JStringType().fromRef(_get_SECURITY_PATCH().object); + + static final _new0 = jniLookup>( + "Build_VERSION__new0") + .asFunction(); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory Build_VERSION() { + return Build_VERSION.fromRef(_new0().object); + } +} + +final class $Build_VERSIONType extends jni.JObjType { + const $Build_VERSIONType(); + + @override + String get signature => r"Landroid/os/Build$VERSION;"; + + @override + Build_VERSION fromRef(jni.JObjectPtr ref) => Build_VERSION.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($Build_VERSIONType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($Build_VERSIONType) && + other is $Build_VERSIONType; + } +} + +/// from: android.os.Build$VERSION_CODES +class Build_VERSION_CODES extends jni.JObject { + @override + late final jni.JObjType $type = type; + + Build_VERSION_CODES.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $Build_VERSION_CODESType(); + + /// from: static public final int BASE + static const BASE = 1; + + /// from: static public final int BASE_1_1 + static const BASE_1_1 = 2; + + /// from: static public final int CUPCAKE + static const CUPCAKE = 3; + + /// from: static public final int CUR_DEVELOPMENT + static const CUR_DEVELOPMENT = 10000; + + /// from: static public final int DONUT + static const DONUT = 4; + + /// from: static public final int ECLAIR + static const ECLAIR = 5; + + /// from: static public final int ECLAIR_0_1 + static const ECLAIR_0_1 = 6; + + /// from: static public final int ECLAIR_MR1 + static const ECLAIR_MR1 = 7; + + /// from: static public final int FROYO + static const FROYO = 8; + + /// from: static public final int GINGERBREAD + static const GINGERBREAD = 9; + + /// from: static public final int GINGERBREAD_MR1 + static const GINGERBREAD_MR1 = 10; + + /// from: static public final int HONEYCOMB + static const HONEYCOMB = 11; + + /// from: static public final int HONEYCOMB_MR1 + static const HONEYCOMB_MR1 = 12; + + /// from: static public final int HONEYCOMB_MR2 + static const HONEYCOMB_MR2 = 13; + + /// from: static public final int ICE_CREAM_SANDWICH + static const ICE_CREAM_SANDWICH = 14; + + /// from: static public final int ICE_CREAM_SANDWICH_MR1 + static const ICE_CREAM_SANDWICH_MR1 = 15; + + /// from: static public final int JELLY_BEAN + static const JELLY_BEAN = 16; + + /// from: static public final int JELLY_BEAN_MR1 + static const JELLY_BEAN_MR1 = 17; + + /// from: static public final int JELLY_BEAN_MR2 + static const JELLY_BEAN_MR2 = 18; + + /// from: static public final int KITKAT + static const KITKAT = 19; + + /// from: static public final int KITKAT_WATCH + static const KITKAT_WATCH = 20; + + /// from: static public final int LOLLIPOP + static const LOLLIPOP = 21; + + /// from: static public final int LOLLIPOP_MR1 + static const LOLLIPOP_MR1 = 22; + + /// from: static public final int M + static const M = 23; + + /// from: static public final int N + static const N = 24; + + /// from: static public final int N_MR1 + static const N_MR1 = 25; + + /// from: static public final int O + static const O = 26; + + /// from: static public final int O_MR1 + static const O_MR1 = 27; + + /// from: static public final int P + static const P = 28; + + /// from: static public final int Q + static const Q = 29; + + /// from: static public final int R + static const R = 30; + + /// from: static public final int S + static const S = 31; + + /// from: static public final int S_V2 + static const S_V2 = 32; + + /// from: static public final int TIRAMISU + static const TIRAMISU = 33; + + static final _new0 = jniLookup>( + "Build_VERSION_CODES__new0") + .asFunction(); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory Build_VERSION_CODES() { + return Build_VERSION_CODES.fromRef(_new0().object); + } +} + +final class $Build_VERSION_CODESType extends jni.JObjType { + const $Build_VERSION_CODESType(); + + @override + String get signature => r"Landroid/os/Build$VERSION_CODES;"; + + @override + Build_VERSION_CODES fromRef(jni.JObjectPtr ref) => + Build_VERSION_CODES.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($Build_VERSION_CODESType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($Build_VERSION_CODESType) && + other is $Build_VERSION_CODESType; + } +} + +/// from: android.os.Build +class Build extends jni.JObject { + @override + late final jni.JObjType $type = type; + + Build.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $BuildType(); + static final _get_BOARD = + jniLookup>( + "get_Build__BOARD") + .asFunction(); + + /// from: static public final java.lang.String BOARD + /// The returned object must be released after use, by calling the [release] method. + static jni.JString get BOARD => + const jni.JStringType().fromRef(_get_BOARD().object); + + static final _get_BOOTLOADER = + jniLookup>( + "get_Build__BOOTLOADER") + .asFunction(); + + /// from: static public final java.lang.String BOOTLOADER + /// The returned object must be released after use, by calling the [release] method. + static jni.JString get BOOTLOADER => + const jni.JStringType().fromRef(_get_BOOTLOADER().object); + + static final _get_BRAND = + jniLookup>( + "get_Build__BRAND") + .asFunction(); + + /// from: static public final java.lang.String BRAND + /// The returned object must be released after use, by calling the [release] method. + static jni.JString get BRAND => + const jni.JStringType().fromRef(_get_BRAND().object); + + static final _get_CPU_ABI = + jniLookup>( + "get_Build__CPU_ABI") + .asFunction(); + + /// from: static public final java.lang.String CPU_ABI + /// The returned object must be released after use, by calling the [release] method. + static jni.JString get CPU_ABI => + const jni.JStringType().fromRef(_get_CPU_ABI().object); + + static final _get_CPU_ABI2 = + jniLookup>( + "get_Build__CPU_ABI2") + .asFunction(); + + /// from: static public final java.lang.String CPU_ABI2 + /// The returned object must be released after use, by calling the [release] method. + static jni.JString get CPU_ABI2 => + const jni.JStringType().fromRef(_get_CPU_ABI2().object); + + static final _get_DEVICE = + jniLookup>( + "get_Build__DEVICE") + .asFunction(); + + /// from: static public final java.lang.String DEVICE + /// The returned object must be released after use, by calling the [release] method. + static jni.JString get DEVICE => + const jni.JStringType().fromRef(_get_DEVICE().object); + + static final _get_DISPLAY = + jniLookup>( + "get_Build__DISPLAY") + .asFunction(); + + /// from: static public final java.lang.String DISPLAY + /// The returned object must be released after use, by calling the [release] method. + static jni.JString get DISPLAY => + const jni.JStringType().fromRef(_get_DISPLAY().object); + + static final _get_FINGERPRINT = + jniLookup>( + "get_Build__FINGERPRINT") + .asFunction(); + + /// from: static public final java.lang.String FINGERPRINT + /// The returned object must be released after use, by calling the [release] method. + static jni.JString get FINGERPRINT => + const jni.JStringType().fromRef(_get_FINGERPRINT().object); + + static final _get_HARDWARE = + jniLookup>( + "get_Build__HARDWARE") + .asFunction(); + + /// from: static public final java.lang.String HARDWARE + /// The returned object must be released after use, by calling the [release] method. + static jni.JString get HARDWARE => + const jni.JStringType().fromRef(_get_HARDWARE().object); + + static final _get_HOST = + jniLookup>("get_Build__HOST") + .asFunction(); + + /// from: static public final java.lang.String HOST + /// The returned object must be released after use, by calling the [release] method. + static jni.JString get HOST => + const jni.JStringType().fromRef(_get_HOST().object); + + static final _get_ID = + jniLookup>("get_Build__ID") + .asFunction(); + + /// from: static public final java.lang.String ID + /// The returned object must be released after use, by calling the [release] method. + static jni.JString get ID => + const jni.JStringType().fromRef(_get_ID().object); + + static final _get_MANUFACTURER = + jniLookup>( + "get_Build__MANUFACTURER") + .asFunction(); + + /// from: static public final java.lang.String MANUFACTURER + /// The returned object must be released after use, by calling the [release] method. + static jni.JString get MANUFACTURER => + const jni.JStringType().fromRef(_get_MANUFACTURER().object); + + static final _get_MODEL = + jniLookup>( + "get_Build__MODEL") + .asFunction(); + + /// from: static public final java.lang.String MODEL + /// The returned object must be released after use, by calling the [release] method. + static jni.JString get MODEL => + const jni.JStringType().fromRef(_get_MODEL().object); + + static final _get_ODM_SKU = + jniLookup>( + "get_Build__ODM_SKU") + .asFunction(); + + /// from: static public final java.lang.String ODM_SKU + /// The returned object must be released after use, by calling the [release] method. + static jni.JString get ODM_SKU => + const jni.JStringType().fromRef(_get_ODM_SKU().object); + + static final _get_PRODUCT = + jniLookup>( + "get_Build__PRODUCT") + .asFunction(); + + /// from: static public final java.lang.String PRODUCT + /// The returned object must be released after use, by calling the [release] method. + static jni.JString get PRODUCT => + const jni.JStringType().fromRef(_get_PRODUCT().object); + + static final _get_RADIO = + jniLookup>( + "get_Build__RADIO") + .asFunction(); + + /// from: static public final java.lang.String RADIO + /// The returned object must be released after use, by calling the [release] method. + static jni.JString get RADIO => + const jni.JStringType().fromRef(_get_RADIO().object); + + static final _get_SERIAL = + jniLookup>( + "get_Build__SERIAL") + .asFunction(); + + /// from: static public final java.lang.String SERIAL + /// The returned object must be released after use, by calling the [release] method. + static jni.JString get SERIAL => + const jni.JStringType().fromRef(_get_SERIAL().object); + + static final _get_SKU = + jniLookup>("get_Build__SKU") + .asFunction(); + + /// from: static public final java.lang.String SKU + /// The returned object must be released after use, by calling the [release] method. + static jni.JString get SKU => + const jni.JStringType().fromRef(_get_SKU().object); + + static final _get_SOC_MANUFACTURER = + jniLookup>( + "get_Build__SOC_MANUFACTURER") + .asFunction(); + + /// from: static public final java.lang.String SOC_MANUFACTURER + /// The returned object must be released after use, by calling the [release] method. + static jni.JString get SOC_MANUFACTURER => + const jni.JStringType().fromRef(_get_SOC_MANUFACTURER().object); + + static final _get_SOC_MODEL = + jniLookup>( + "get_Build__SOC_MODEL") + .asFunction(); + + /// from: static public final java.lang.String SOC_MODEL + /// The returned object must be released after use, by calling the [release] method. + static jni.JString get SOC_MODEL => + const jni.JStringType().fromRef(_get_SOC_MODEL().object); + + static final _get_SUPPORTED_32_BIT_ABIS = + jniLookup>( + "get_Build__SUPPORTED_32_BIT_ABIS") + .asFunction(); + + /// from: static public final java.lang.String[] SUPPORTED_32_BIT_ABIS + /// The returned object must be released after use, by calling the [release] method. + static jni.JArray get SUPPORTED_32_BIT_ABIS => + const jni.JArrayType(jni.JStringType()) + .fromRef(_get_SUPPORTED_32_BIT_ABIS().object); + + static final _get_SUPPORTED_64_BIT_ABIS = + jniLookup>( + "get_Build__SUPPORTED_64_BIT_ABIS") + .asFunction(); + + /// from: static public final java.lang.String[] SUPPORTED_64_BIT_ABIS + /// The returned object must be released after use, by calling the [release] method. + static jni.JArray get SUPPORTED_64_BIT_ABIS => + const jni.JArrayType(jni.JStringType()) + .fromRef(_get_SUPPORTED_64_BIT_ABIS().object); + + static final _get_SUPPORTED_ABIS = + jniLookup>( + "get_Build__SUPPORTED_ABIS") + .asFunction(); + + /// from: static public final java.lang.String[] SUPPORTED_ABIS + /// The returned object must be released after use, by calling the [release] method. + static jni.JArray get SUPPORTED_ABIS => + const jni.JArrayType(jni.JStringType()) + .fromRef(_get_SUPPORTED_ABIS().object); + + static final _get_TAGS = + jniLookup>("get_Build__TAGS") + .asFunction(); + + /// from: static public final java.lang.String TAGS + /// The returned object must be released after use, by calling the [release] method. + static jni.JString get TAGS => + const jni.JStringType().fromRef(_get_TAGS().object); + + static final _get_TIME = + jniLookup>("get_Build__TIME") + .asFunction(); + + /// from: static public final long TIME + static int get TIME => _get_TIME().long; + + static final _get_TYPE = + jniLookup>("get_Build__TYPE") + .asFunction(); + + /// from: static public final java.lang.String TYPE + /// The returned object must be released after use, by calling the [release] method. + static jni.JString get TYPE => + const jni.JStringType().fromRef(_get_TYPE().object); + + /// from: static public final java.lang.String UNKNOWN + static const UNKNOWN = r"""unknown"""; + + static final _get_USER = + jniLookup>("get_Build__USER") + .asFunction(); + + /// from: static public final java.lang.String USER + /// The returned object must be released after use, by calling the [release] method. + static jni.JString get USER => + const jni.JStringType().fromRef(_get_USER().object); + + static final _new0 = + jniLookup>("Build__new0") + .asFunction(); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory Build() { + return Build.fromRef(_new0().object); + } + + static final _getSerial = + jniLookup>( + "Build__getSerial") + .asFunction(); + + /// from: static public java.lang.String getSerial() + /// The returned object must be released after use, by calling the [release] method. + static jni.JString getSerial() { + return const jni.JStringType().fromRef(_getSerial().object); + } + + static final _getFingerprintedPartitions = + jniLookup>( + "Build__getFingerprintedPartitions") + .asFunction(); + + /// from: static public java.util.List getFingerprintedPartitions() + /// The returned object must be released after use, by calling the [release] method. + static jni.JList getFingerprintedPartitions() { + return const jni.JListType($Build_PartitionType()) + .fromRef(_getFingerprintedPartitions().object); + } + + static final _getRadioVersion = + jniLookup>( + "Build__getRadioVersion") + .asFunction(); + + /// from: static public java.lang.String getRadioVersion() + /// The returned object must be released after use, by calling the [release] method. + static jni.JString getRadioVersion() { + return const jni.JStringType().fromRef(_getRadioVersion().object); + } +} + +final class $BuildType extends jni.JObjType { + const $BuildType(); + + @override + String get signature => r"Landroid/os/Build;"; + + @override + Build fromRef(jni.JObjectPtr ref) => Build.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($BuildType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($BuildType) && other is $BuildType; + } +} + +/// from: java.util.HashMap +class HashMap<$K extends jni.JObject, $V extends jni.JObject> + extends jni.JObject { + @override + late final jni.JObjType> $type = type(K, V); + + final jni.JObjType<$K> K; + final jni.JObjType<$V> V; + + HashMap.fromRef( + this.K, + this.V, + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static $HashMapType<$K, $V> + type<$K extends jni.JObject, $V extends jni.JObject>( + jni.JObjType<$K> K, + jni.JObjType<$V> V, + ) { + return $HashMapType( + K, + V, + ); + } + + static final _new0 = jniLookup< + ffi.NativeFunction>( + "HashMap__new0") + .asFunction(); + + /// from: public void (int i, float f) + /// The returned object must be released after use, by calling the [release] method. + factory HashMap( + int i, + double f, { + required jni.JObjType<$K> K, + required jni.JObjType<$V> V, + }) { + return HashMap.fromRef(K, V, _new0(i, f).object); + } + + static final _new1 = + jniLookup>( + "HashMap__new1") + .asFunction(); + + /// from: public void (int i) + /// The returned object must be released after use, by calling the [release] method. + factory HashMap.new1( + int i, { + required jni.JObjType<$K> K, + required jni.JObjType<$V> V, + }) { + return HashMap.fromRef(K, V, _new1(i).object); + } + + static final _new2 = + jniLookup>("HashMap__new2") + .asFunction(); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory HashMap.new2({ + required jni.JObjType<$K> K, + required jni.JObjType<$V> V, + }) { + return HashMap.fromRef(K, V, _new2().object); + } + + static final _new3 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer)>>("HashMap__new3") + .asFunction)>(); + + /// from: public void (java.util.Map map) + /// The returned object must be released after use, by calling the [release] method. + factory HashMap.new3( + jni.JMap<$K, $V> map, { + jni.JObjType<$K>? K, + jni.JObjType<$V>? V, + }) { + K ??= jni.lowestCommonSuperType([ + (map.$type as jni.JMapType).K, + ]) as jni.JObjType<$K>; + V ??= jni.lowestCommonSuperType([ + (map.$type as jni.JMapType).V, + ]) as jni.JObjType<$V>; + return HashMap.fromRef(K, V, _new3(map.reference).object); + } + + static final _size = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer)>>("HashMap__size") + .asFunction)>(); + + /// from: public int size() + int size() { + return _size(reference).integer; + } + + static final _isEmpty = jniLookup< + ffi + .NativeFunction)>>( + "HashMap__isEmpty") + .asFunction)>(); + + /// from: public boolean isEmpty() + bool isEmpty() { + return _isEmpty(reference).boolean; + } + + static final _get0 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("HashMap__get0") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public V get(java.lang.Object object) + /// The returned object must be released after use, by calling the [release] method. + $V get0( + jni.JObject object, + ) { + return V.fromRef(_get0(reference, object.reference).object); + } + + static final _containsKey = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("HashMap__containsKey") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public boolean containsKey(java.lang.Object object) + bool containsKey( + jni.JObject object, + ) { + return _containsKey(reference, object.reference).boolean; + } + + static final _put = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>("HashMap__put") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); + + /// from: public V put(K object, V object1) + /// The returned object must be released after use, by calling the [release] method. + $V put( + $K object, + $V object1, + ) { + return V + .fromRef(_put(reference, object.reference, object1.reference).object); + } + + static final _putAll = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("HashMap__putAll") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void putAll(java.util.Map map) + void putAll( + jni.JMap<$K, $V> map, + ) { + return _putAll(reference, map.reference).check(); + } + + static final _remove = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("HashMap__remove") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public V remove(java.lang.Object object) + /// The returned object must be released after use, by calling the [release] method. + $V remove( + jni.JObject object, + ) { + return V.fromRef(_remove(reference, object.reference).object); + } + + static final _clear = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer)>>("HashMap__clear") + .asFunction)>(); + + /// from: public void clear() + void clear() { + return _clear(reference).check(); + } + + static final _containsValue = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("HashMap__containsValue") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public boolean containsValue(java.lang.Object object) + bool containsValue( + jni.JObject object, + ) { + return _containsValue(reference, object.reference).boolean; + } + + static final _keySet = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer)>>("HashMap__keySet") + .asFunction)>(); + + /// from: public java.util.Set keySet() + /// The returned object must be released after use, by calling the [release] method. + jni.JSet<$K> keySet() { + return jni.JSetType(K).fromRef(_keySet(reference).object); + } + + static final _values = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer)>>("HashMap__values") + .asFunction)>(); + + /// from: public java.util.Collection values() + /// The returned object must be released after use, by calling the [release] method. + jni.JObject values() { + return const jni.JObjectType().fromRef(_values(reference).object); + } + + static final _entrySet = jniLookup< + ffi + .NativeFunction)>>( + "HashMap__entrySet") + .asFunction)>(); + + /// from: public java.util.Set entrySet() + /// The returned object must be released after use, by calling the [release] method. + jni.JSet entrySet() { + return const jni.JSetType(jni.JObjectType()) + .fromRef(_entrySet(reference).object); + } + + static final _getOrDefault = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>("HashMap__getOrDefault") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); + + /// from: public V getOrDefault(java.lang.Object object, V object1) + /// The returned object must be released after use, by calling the [release] method. + $V getOrDefault( + jni.JObject object, + $V object1, + ) { + return V.fromRef( + _getOrDefault(reference, object.reference, object1.reference).object); + } + + static final _putIfAbsent = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>("HashMap__putIfAbsent") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); + + /// from: public V putIfAbsent(K object, V object1) + /// The returned object must be released after use, by calling the [release] method. + $V putIfAbsent( + $K object, + $V object1, + ) { + return V.fromRef( + _putIfAbsent(reference, object.reference, object1.reference).object); + } + + static final _remove1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>("HashMap__remove1") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); + + /// from: public boolean remove(java.lang.Object object, java.lang.Object object1) + bool remove1( + jni.JObject object, + jni.JObject object1, + ) { + return _remove1(reference, object.reference, object1.reference).boolean; + } + + static final _replace = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>("HashMap__replace") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer, ffi.Pointer)>(); + + /// from: public boolean replace(K object, V object1, V object2) + bool replace( + $K object, + $V object1, + $V object2, + ) { + return _replace( + reference, object.reference, object1.reference, object2.reference) + .boolean; + } + + static final _replace1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>("HashMap__replace1") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); + + /// from: public V replace(K object, V object1) + /// The returned object must be released after use, by calling the [release] method. + $V replace1( + $K object, + $V object1, + ) { + return V.fromRef( + _replace1(reference, object.reference, object1.reference).object); + } + + static final _computeIfAbsent = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>("HashMap__computeIfAbsent") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); + + /// from: public V computeIfAbsent(K object, java.util.function.Function function) + /// The returned object must be released after use, by calling the [release] method. + $V computeIfAbsent( + $K object, + jni.JObject function, + ) { + return V.fromRef( + _computeIfAbsent(reference, object.reference, function.reference) + .object); + } + + static final _computeIfPresent = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>("HashMap__computeIfPresent") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); + + /// from: public V computeIfPresent(K object, java.util.function.BiFunction biFunction) + /// The returned object must be released after use, by calling the [release] method. + $V computeIfPresent( + $K object, + jni.JObject biFunction, + ) { + return V.fromRef( + _computeIfPresent(reference, object.reference, biFunction.reference) + .object); + } + + static final _compute = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>("HashMap__compute") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); + + /// from: public V compute(K object, java.util.function.BiFunction biFunction) + /// The returned object must be released after use, by calling the [release] method. + $V compute( + $K object, + jni.JObject biFunction, + ) { + return V.fromRef( + _compute(reference, object.reference, biFunction.reference).object); + } + + static final _merge = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>("HashMap__merge") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer, ffi.Pointer)>(); + + /// from: public V merge(K object, V object1, java.util.function.BiFunction biFunction) + /// The returned object must be released after use, by calling the [release] method. + $V merge( + $K object, + $V object1, + jni.JObject biFunction, + ) { + return V.fromRef(_merge(reference, object.reference, object1.reference, + biFunction.reference) + .object); + } + + static final _forEach = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("HashMap__forEach") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void forEach(java.util.function.BiConsumer biConsumer) + void forEach( + jni.JObject biConsumer, + ) { + return _forEach(reference, biConsumer.reference).check(); + } + + static final _replaceAll = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("HashMap__replaceAll") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void replaceAll(java.util.function.BiFunction biFunction) + void replaceAll( + jni.JObject biFunction, + ) { + return _replaceAll(reference, biFunction.reference).check(); + } + + static final _clone = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer)>>("HashMap__clone") + .asFunction)>(); + + /// from: public java.lang.Object clone() + /// The returned object must be released after use, by calling the [release] method. + jni.JObject clone() { + return const jni.JObjectType().fromRef(_clone(reference).object); + } +} + +final class $HashMapType<$K extends jni.JObject, $V extends jni.JObject> + extends jni.JObjType> { + final jni.JObjType<$K> K; + final jni.JObjType<$V> V; + + const $HashMapType( + this.K, + this.V, + ); + + @override + String get signature => r"Ljava/util/HashMap;"; + + @override + HashMap<$K, $V> fromRef(jni.JObjectPtr ref) => HashMap.fromRef(K, V, ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => Object.hash($HashMapType, K, V); + + @override + bool operator ==(Object other) { + return other.runtimeType == ($HashMapType<$K, $V>) && + other is $HashMapType<$K, $V> && + K == other.K && + V == other.V; + } +} diff --git a/pkgs/jnigen/example/in_app_java/lib/main.dart b/pkgs/jnigen/example/in_app_java/lib/main.dart new file mode 100644 index 000000000..22575817b --- /dev/null +++ b/pkgs/jnigen/example/in_app_java/lib/main.dart @@ -0,0 +1,86 @@ +// 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. + +import 'package:flutter/material.dart'; +import 'package:jni/jni.dart'; + +// The hierarchy created in generated code will mirror the java package +// structure. +import 'android_utils.dart'; + +JObject activity = JObject.fromRef(Jni.getCurrentActivity()); +JObject context = JObject.fromRef(Jni.getCachedApplicationContext()); + +final hashmap = HashMap.new2(K: JString.type, V: JString.type); + +final emojiCompat = EmojiCompat.get0(); + +extension IntX on int { + JString toJString() { + return toString().toJString(); + } +} + +const sunglassEmoji = "😎"; + +/// Display device model number and the number of times this was called +/// as Toast. +void showToast() { + final toastCount = + hashmap.getOrDefault("toastCount".toJString(), 0.toJString()); + final newToastCount = (int.parse(toastCount.toDartString()) + 1).toJString(); + hashmap.put("toastCount".toJString(), newToastCount); + final emoji = emojiCompat.hasEmojiGlyph(sunglassEmoji.toJString()) + ? sunglassEmoji + : ':cool:'; + final message = + '${newToastCount.toDartString()} - ${Build.MODEL.toDartString()} $emoji'; + AndroidUtils.showToast(activity, message.toJString(), 0); +} + +void main() { + EmojiCompat.init(context); + runApp(const MyApp()); +} + +class MyApp extends StatelessWidget { + const MyApp({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + theme: ThemeData( + primarySwatch: Colors.teal, + ), + home: const MyHomePage(title: 'Flutter Demo Home Page'), + ); + } +} + +class MyHomePage extends StatelessWidget { + const MyHomePage({Key? key, required this.title}) : super(key: key); + + final String title; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(title), + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ElevatedButton( + child: const Text('Show Device Model'), + onPressed: () => showToast(), + ), + ], + ), + ), + ); + } +} diff --git a/pkgs/jnigen/example/in_app_java/pubspec.yaml b/pkgs/jnigen/example/in_app_java/pubspec.yaml new file mode 100644 index 000000000..321cc99bc --- /dev/null +++ b/pkgs/jnigen/example/in_app_java/pubspec.yaml @@ -0,0 +1,67 @@ +name: in_app_java +description: | + Example on how to use jnigen to bridge between java and dart in a flutter + project. + +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +version: 1.0.0+1 + +environment: + sdk: '>=3.1.0 <4.0.0' + +dependencies: + flutter: + sdk: flutter + jni: + path: ../../../jni/ + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.2 + +dev_dependencies: + flutter_test: + sdk: flutter + jnigen: + path: ../../ + + flutter_lints: ^2.0.0 + +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/assets-and-images/#from-packages + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/custom-fonts/#from-packages diff --git a/pkgs/jnigen/example/in_app_java/src/android_utils/.clang-format b/pkgs/jnigen/example/in_app_java/src/android_utils/.clang-format new file mode 100644 index 000000000..a256c2f09 --- /dev/null +++ b/pkgs/jnigen/example/in_app_java/src/android_utils/.clang-format @@ -0,0 +1,15 @@ +# From dart SDK: https://github.com/dart-lang/sdk/blob/main/.clang-format + +# Defines the Chromium style for automatic reformatting. +# http://clang.llvm.org/docs/ClangFormatStyleOptions.html +BasedOnStyle: Chromium + +# clang-format doesn't seem to do a good job of this for longer comments. +ReflowComments: 'false' + +# We have lots of these. Though we need to put them all in curly braces, +# clang-format can't do that. +AllowShortIfStatementsOnASingleLine: 'true' + +# Put escaped newlines into the rightmost column. +AlignEscapedNewlinesLeft: false diff --git a/pkgs/jnigen/example/in_app_java/src/android_utils/CMakeLists.txt b/pkgs/jnigen/example/in_app_java/src/android_utils/CMakeLists.txt new file mode 100644 index 000000000..0c47c280c --- /dev/null +++ b/pkgs/jnigen/example/in_app_java/src/android_utils/CMakeLists.txt @@ -0,0 +1,32 @@ +# jni_native_build (Build with jni:setup. Do not delete this line.) + +# The Flutter tooling requires that developers have CMake 3.10 or later +# installed. You should not increase this version, as doing so will cause +# the plugin to fail to compile for some customers of the plugin. +cmake_minimum_required(VERSION 3.10) + +project(android_utils VERSION 0.0.1 LANGUAGES C) + +add_library(android_utils SHARED + "./android_utils.c" +) + +set_target_properties(android_utils PROPERTIES + OUTPUT_NAME "android_utils" +) + +target_compile_definitions(android_utils PUBLIC DART_SHARED_LIB) + +if(WIN32) + set_target_properties(${TARGET_NAME} PROPERTIES + LINK_FLAGS "/DELAYLOAD:jvm.dll") +endif() + +if (ANDROID) + target_link_libraries(android_utils log) +else() + find_package(Java REQUIRED) + find_package(JNI REQUIRED) + include_directories(${JNI_INCLUDE_DIRS}) + target_link_libraries(android_utils ${JNI_LIBRARIES}) +endif() 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 new file mode 100644 index 000000000..983838bc9 --- /dev/null +++ b/pkgs/jnigen/example/in_app_java/src/android_utils/android_utils.c @@ -0,0 +1,2513 @@ +// Autogenerated by jnigen. DO NOT EDIT! + +#include +#include "dartjni.h" +#include "jni.h" + +thread_local JNIEnv* jniEnv; +JniContext* jni; + +JniContext* (*context_getter)(void); +JNIEnv* (*env_getter)(void); + +void setJniGetters(JniContext* (*cg)(void), JNIEnv* (*eg)(void)) { + context_getter = cg; + env_getter = eg; +} + +// com.example.in_app_java.AndroidUtils +jclass _c_AndroidUtils = NULL; + +jmethodID _m_AndroidUtils__showToast = NULL; +FFI_PLUGIN_EXPORT +JniResult AndroidUtils__showToast(jobject mainActivity, + jobject text, + int32_t duration) { + load_env(); + load_class_global_ref(&_c_AndroidUtils, + "com/example/in_app_java/AndroidUtils"); + if (_c_AndroidUtils == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_AndroidUtils, &_m_AndroidUtils__showToast, "showToast", + "(Landroid/app/Activity;Ljava/lang/CharSequence;I)V"); + if (_m_AndroidUtils__showToast == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallStaticVoidMethod(jniEnv, _c_AndroidUtils, + _m_AndroidUtils__showToast, mainActivity, + text, duration); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +// androidx.emoji2.text.EmojiCompat +jclass _c_EmojiCompat = NULL; + +jmethodID _m_EmojiCompat__init = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat__init(jobject context) { + load_env(); + load_class_global_ref(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat"); + if (_c_EmojiCompat == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method( + _c_EmojiCompat, &_m_EmojiCompat__init, "init", + "(Landroid/content/Context;)Landroidx/emoji2/text/EmojiCompat;"); + if (_m_EmojiCompat__init == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_EmojiCompat, _m_EmojiCompat__init, context); + return to_global_ref_result(_result); +} + +jmethodID _m_EmojiCompat__init1 = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat__init1(jobject context, jobject defaultFactory) { + load_env(); + load_class_global_ref(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat"); + if (_c_EmojiCompat == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_EmojiCompat, &_m_EmojiCompat__init1, "init", + "(Landroid/content/Context;Landroidx/emoji2/text/" + "DefaultEmojiCompatConfig$DefaultEmojiCompatConfigFactory;" + ")Landroidx/emoji2/text/EmojiCompat;"); + if (_m_EmojiCompat__init1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_EmojiCompat, _m_EmojiCompat__init1, context, defaultFactory); + return to_global_ref_result(_result); +} + +jmethodID _m_EmojiCompat__init2 = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat__init2(jobject config) { + load_env(); + load_class_global_ref(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat"); + if (_c_EmojiCompat == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_EmojiCompat, &_m_EmojiCompat__init2, "init", + "(Landroidx/emoji2/text/EmojiCompat$Config;)Landroidx/" + "emoji2/text/EmojiCompat;"); + if (_m_EmojiCompat__init2 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_EmojiCompat, _m_EmojiCompat__init2, config); + return to_global_ref_result(_result); +} + +jmethodID _m_EmojiCompat__isConfigured = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat__isConfigured() { + load_env(); + load_class_global_ref(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat"); + if (_c_EmojiCompat == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_EmojiCompat, &_m_EmojiCompat__isConfigured, + "isConfigured", "()Z"); + if (_m_EmojiCompat__isConfigured == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallStaticBooleanMethod( + jniEnv, _c_EmojiCompat, _m_EmojiCompat__isConfigured); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_EmojiCompat__reset = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat__reset(jobject config) { + load_env(); + load_class_global_ref(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat"); + if (_c_EmojiCompat == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_EmojiCompat, &_m_EmojiCompat__reset, "reset", + "(Landroidx/emoji2/text/EmojiCompat$Config;)Landroidx/" + "emoji2/text/EmojiCompat;"); + if (_m_EmojiCompat__reset == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_EmojiCompat, _m_EmojiCompat__reset, config); + return to_global_ref_result(_result); +} + +jmethodID _m_EmojiCompat__reset1 = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat__reset1(jobject emojiCompat) { + load_env(); + load_class_global_ref(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat"); + if (_c_EmojiCompat == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method( + _c_EmojiCompat, &_m_EmojiCompat__reset1, "reset", + "(Landroidx/emoji2/text/EmojiCompat;)Landroidx/emoji2/text/EmojiCompat;"); + if (_m_EmojiCompat__reset1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_EmojiCompat, _m_EmojiCompat__reset1, emojiCompat); + return to_global_ref_result(_result); +} + +jmethodID _m_EmojiCompat__skipDefaultConfigurationLookup = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat__skipDefaultConfigurationLookup(uint8_t shouldSkip) { + load_env(); + load_class_global_ref(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat"); + if (_c_EmojiCompat == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_EmojiCompat, + &_m_EmojiCompat__skipDefaultConfigurationLookup, + "skipDefaultConfigurationLookup", "(Z)V"); + if (_m_EmojiCompat__skipDefaultConfigurationLookup == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallStaticVoidMethod( + jniEnv, _c_EmojiCompat, _m_EmojiCompat__skipDefaultConfigurationLookup, + shouldSkip); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_EmojiCompat__get0 = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat__get0() { + load_env(); + load_class_global_ref(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat"); + if (_c_EmojiCompat == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_EmojiCompat, &_m_EmojiCompat__get0, "get", + "()Landroidx/emoji2/text/EmojiCompat;"); + if (_m_EmojiCompat__get0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod(jniEnv, _c_EmojiCompat, + _m_EmojiCompat__get0); + return to_global_ref_result(_result); +} + +jmethodID _m_EmojiCompat__load = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat__load(jobject self_) { + load_env(); + load_class_global_ref(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat"); + if (_c_EmojiCompat == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat, &_m_EmojiCompat__load, "load", "()V"); + if (_m_EmojiCompat__load == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_EmojiCompat__load); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_EmojiCompat__registerInitCallback = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat__registerInitCallback(jobject self_, + jobject initCallback) { + load_env(); + load_class_global_ref(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat"); + if (_c_EmojiCompat == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat, &_m_EmojiCompat__registerInitCallback, + "registerInitCallback", + "(Landroidx/emoji2/text/EmojiCompat$InitCallback;)V"); + if (_m_EmojiCompat__registerInitCallback == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_EmojiCompat__registerInitCallback, + initCallback); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_EmojiCompat__unregisterInitCallback = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat__unregisterInitCallback(jobject self_, + jobject initCallback) { + load_env(); + load_class_global_ref(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat"); + if (_c_EmojiCompat == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat, &_m_EmojiCompat__unregisterInitCallback, + "unregisterInitCallback", + "(Landroidx/emoji2/text/EmojiCompat$InitCallback;)V"); + if (_m_EmojiCompat__unregisterInitCallback == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod( + jniEnv, self_, _m_EmojiCompat__unregisterInitCallback, initCallback); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_EmojiCompat__getLoadState = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat__getLoadState(jobject self_) { + load_env(); + load_class_global_ref(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat"); + if (_c_EmojiCompat == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat, &_m_EmojiCompat__getLoadState, "getLoadState", + "()I"); + if (_m_EmojiCompat__getLoadState == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = + (*jniEnv)->CallIntMethod(jniEnv, self_, _m_EmojiCompat__getLoadState); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_EmojiCompat__isEmojiSpanIndicatorEnabled = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat__isEmojiSpanIndicatorEnabled(jobject self_) { + load_env(); + load_class_global_ref(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat"); + if (_c_EmojiCompat == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat, &_m_EmojiCompat__isEmojiSpanIndicatorEnabled, + "isEmojiSpanIndicatorEnabled", "()Z"); + if (_m_EmojiCompat__isEmojiSpanIndicatorEnabled == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod( + jniEnv, self_, _m_EmojiCompat__isEmojiSpanIndicatorEnabled); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_EmojiCompat__getEmojiSpanIndicatorColor = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat__getEmojiSpanIndicatorColor(jobject self_) { + load_env(); + load_class_global_ref(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat"); + if (_c_EmojiCompat == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat, &_m_EmojiCompat__getEmojiSpanIndicatorColor, + "getEmojiSpanIndicatorColor", "()I"); + if (_m_EmojiCompat__getEmojiSpanIndicatorColor == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = (*jniEnv)->CallIntMethod( + jniEnv, self_, _m_EmojiCompat__getEmojiSpanIndicatorColor); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_EmojiCompat__getEmojiStart = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat__getEmojiStart(jobject self_, + jobject charSequence, + int32_t offset) { + load_env(); + load_class_global_ref(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat"); + if (_c_EmojiCompat == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat, &_m_EmojiCompat__getEmojiStart, "getEmojiStart", + "(Ljava/lang/CharSequence;I)I"); + if (_m_EmojiCompat__getEmojiStart == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = (*jniEnv)->CallIntMethod( + jniEnv, self_, _m_EmojiCompat__getEmojiStart, charSequence, offset); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_EmojiCompat__getEmojiEnd = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat__getEmojiEnd(jobject self_, + jobject charSequence, + int32_t offset) { + load_env(); + load_class_global_ref(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat"); + if (_c_EmojiCompat == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat, &_m_EmojiCompat__getEmojiEnd, "getEmojiEnd", + "(Ljava/lang/CharSequence;I)I"); + if (_m_EmojiCompat__getEmojiEnd == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = (*jniEnv)->CallIntMethod( + jniEnv, self_, _m_EmojiCompat__getEmojiEnd, charSequence, offset); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_EmojiCompat__handleOnKeyDown = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat__handleOnKeyDown(jobject editable, + int32_t keyCode, + jobject event) { + load_env(); + load_class_global_ref(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat"); + if (_c_EmojiCompat == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_EmojiCompat, &_m_EmojiCompat__handleOnKeyDown, + "handleOnKeyDown", + "(Landroid/text/Editable;ILandroid/view/KeyEvent;)Z"); + if (_m_EmojiCompat__handleOnKeyDown == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallStaticBooleanMethod( + jniEnv, _c_EmojiCompat, _m_EmojiCompat__handleOnKeyDown, editable, + keyCode, event); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_EmojiCompat__handleDeleteSurroundingText = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat__handleDeleteSurroundingText(jobject inputConnection, + jobject editable, + int32_t beforeLength, + int32_t afterLength, + uint8_t inCodePoints) { + load_env(); + load_class_global_ref(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat"); + if (_c_EmojiCompat == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_EmojiCompat, + &_m_EmojiCompat__handleDeleteSurroundingText, + "handleDeleteSurroundingText", + "(Landroid/view/inputmethod/InputConnection;Landroid/text/" + "Editable;IIZ)Z"); + if (_m_EmojiCompat__handleDeleteSurroundingText == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallStaticBooleanMethod( + jniEnv, _c_EmojiCompat, _m_EmojiCompat__handleDeleteSurroundingText, + inputConnection, editable, beforeLength, afterLength, inCodePoints); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_EmojiCompat__hasEmojiGlyph = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat__hasEmojiGlyph(jobject self_, jobject sequence) { + load_env(); + load_class_global_ref(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat"); + if (_c_EmojiCompat == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat, &_m_EmojiCompat__hasEmojiGlyph, "hasEmojiGlyph", + "(Ljava/lang/CharSequence;)Z"); + if (_m_EmojiCompat__hasEmojiGlyph == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod( + jniEnv, self_, _m_EmojiCompat__hasEmojiGlyph, sequence); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_EmojiCompat__hasEmojiGlyph1 = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat__hasEmojiGlyph1(jobject self_, + jobject sequence, + int32_t metadataVersion) { + load_env(); + load_class_global_ref(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat"); + if (_c_EmojiCompat == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat, &_m_EmojiCompat__hasEmojiGlyph1, "hasEmojiGlyph", + "(Ljava/lang/CharSequence;I)Z"); + if (_m_EmojiCompat__hasEmojiGlyph1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod( + jniEnv, self_, _m_EmojiCompat__hasEmojiGlyph1, sequence, metadataVersion); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_EmojiCompat__getEmojiMatch = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat__getEmojiMatch(jobject self_, + jobject sequence, + int32_t metadataVersion) { + load_env(); + load_class_global_ref(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat"); + if (_c_EmojiCompat == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat, &_m_EmojiCompat__getEmojiMatch, "getEmojiMatch", + "(Ljava/lang/CharSequence;I)I"); + if (_m_EmojiCompat__getEmojiMatch == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = (*jniEnv)->CallIntMethod( + jniEnv, self_, _m_EmojiCompat__getEmojiMatch, sequence, metadataVersion); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_EmojiCompat__process = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat__process(jobject self_, jobject charSequence) { + load_env(); + load_class_global_ref(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat"); + if (_c_EmojiCompat == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat, &_m_EmojiCompat__process, "process", + "(Ljava/lang/CharSequence;)Ljava/lang/CharSequence;"); + if (_m_EmojiCompat__process == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_EmojiCompat__process, charSequence); + return to_global_ref_result(_result); +} + +jmethodID _m_EmojiCompat__process1 = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat__process1(jobject self_, + jobject charSequence, + int32_t start, + int32_t end) { + load_env(); + load_class_global_ref(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat"); + if (_c_EmojiCompat == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat, &_m_EmojiCompat__process1, "process", + "(Ljava/lang/CharSequence;II)Ljava/lang/CharSequence;"); + if (_m_EmojiCompat__process1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_EmojiCompat__process1, charSequence, start, end); + return to_global_ref_result(_result); +} + +jmethodID _m_EmojiCompat__process2 = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat__process2(jobject self_, + jobject charSequence, + int32_t start, + int32_t end, + int32_t maxEmojiCount) { + load_env(); + load_class_global_ref(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat"); + if (_c_EmojiCompat == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat, &_m_EmojiCompat__process2, "process", + "(Ljava/lang/CharSequence;III)Ljava/lang/CharSequence;"); + if (_m_EmojiCompat__process2 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_EmojiCompat__process2, + charSequence, start, end, maxEmojiCount); + return to_global_ref_result(_result); +} + +jmethodID _m_EmojiCompat__process3 = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat__process3(jobject self_, + jobject charSequence, + int32_t start, + int32_t end, + int32_t maxEmojiCount, + int32_t replaceStrategy) { + load_env(); + load_class_global_ref(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat"); + if (_c_EmojiCompat == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat, &_m_EmojiCompat__process3, "process", + "(Ljava/lang/CharSequence;IIII)Ljava/lang/CharSequence;"); + if (_m_EmojiCompat__process3 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_EmojiCompat__process3, charSequence, start, end, + maxEmojiCount, replaceStrategy); + return to_global_ref_result(_result); +} + +jmethodID _m_EmojiCompat__getAssetSignature = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat__getAssetSignature(jobject self_) { + load_env(); + load_class_global_ref(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat"); + if (_c_EmojiCompat == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat, &_m_EmojiCompat__getAssetSignature, + "getAssetSignature", "()Ljava/lang/String;"); + if (_m_EmojiCompat__getAssetSignature == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_EmojiCompat__getAssetSignature); + return to_global_ref_result(_result); +} + +jmethodID _m_EmojiCompat__updateEditorInfo = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat__updateEditorInfo(jobject self_, jobject outAttrs) { + load_env(); + load_class_global_ref(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat"); + if (_c_EmojiCompat == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat, &_m_EmojiCompat__updateEditorInfo, + "updateEditorInfo", "(Landroid/view/inputmethod/EditorInfo;)V"); + if (_m_EmojiCompat__updateEditorInfo == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_EmojiCompat__updateEditorInfo, + outAttrs); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +// androidx.emoji2.text.EmojiCompat$Config +jclass _c_EmojiCompat_Config = NULL; + +jmethodID _m_EmojiCompat_Config__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat_Config__new0(jobject metadataLoader) { + load_env(); + load_class_global_ref(&_c_EmojiCompat_Config, + "androidx/emoji2/text/EmojiCompat$Config"); + if (_c_EmojiCompat_Config == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat_Config, &_m_EmojiCompat_Config__new0, "", + "(Landroidx/emoji2/text/EmojiCompat$MetadataRepoLoader;)V"); + if (_m_EmojiCompat_Config__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->NewObject(jniEnv, _c_EmojiCompat_Config, + _m_EmojiCompat_Config__new0, metadataLoader); + return to_global_ref_result(_result); +} + +jmethodID _m_EmojiCompat_Config__registerInitCallback = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat_Config__registerInitCallback(jobject self_, + jobject initCallback) { + load_env(); + load_class_global_ref(&_c_EmojiCompat_Config, + "androidx/emoji2/text/EmojiCompat$Config"); + if (_c_EmojiCompat_Config == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat_Config, + &_m_EmojiCompat_Config__registerInitCallback, + "registerInitCallback", + "(Landroidx/emoji2/text/EmojiCompat$InitCallback;)Landroidx/" + "emoji2/text/EmojiCompat$Config;"); + if (_m_EmojiCompat_Config__registerInitCallback == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_EmojiCompat_Config__registerInitCallback, initCallback); + return to_global_ref_result(_result); +} + +jmethodID _m_EmojiCompat_Config__unregisterInitCallback = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat_Config__unregisterInitCallback(jobject self_, + jobject initCallback) { + load_env(); + load_class_global_ref(&_c_EmojiCompat_Config, + "androidx/emoji2/text/EmojiCompat$Config"); + if (_c_EmojiCompat_Config == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat_Config, + &_m_EmojiCompat_Config__unregisterInitCallback, + "unregisterInitCallback", + "(Landroidx/emoji2/text/EmojiCompat$InitCallback;)Landroidx/" + "emoji2/text/EmojiCompat$Config;"); + if (_m_EmojiCompat_Config__unregisterInitCallback == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_EmojiCompat_Config__unregisterInitCallback, + initCallback); + return to_global_ref_result(_result); +} + +jmethodID _m_EmojiCompat_Config__setReplaceAll = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat_Config__setReplaceAll(jobject self_, uint8_t replaceAll) { + load_env(); + load_class_global_ref(&_c_EmojiCompat_Config, + "androidx/emoji2/text/EmojiCompat$Config"); + if (_c_EmojiCompat_Config == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat_Config, &_m_EmojiCompat_Config__setReplaceAll, + "setReplaceAll", "(Z)Landroidx/emoji2/text/EmojiCompat$Config;"); + if (_m_EmojiCompat_Config__setReplaceAll == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_EmojiCompat_Config__setReplaceAll, replaceAll); + return to_global_ref_result(_result); +} + +jmethodID _m_EmojiCompat_Config__setUseEmojiAsDefaultStyle = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat_Config__setUseEmojiAsDefaultStyle( + jobject self_, + uint8_t useEmojiAsDefaultStyle) { + load_env(); + load_class_global_ref(&_c_EmojiCompat_Config, + "androidx/emoji2/text/EmojiCompat$Config"); + if (_c_EmojiCompat_Config == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat_Config, + &_m_EmojiCompat_Config__setUseEmojiAsDefaultStyle, + "setUseEmojiAsDefaultStyle", + "(Z)Landroidx/emoji2/text/EmojiCompat$Config;"); + if (_m_EmojiCompat_Config__setUseEmojiAsDefaultStyle == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_EmojiCompat_Config__setUseEmojiAsDefaultStyle, + useEmojiAsDefaultStyle); + return to_global_ref_result(_result); +} + +jmethodID _m_EmojiCompat_Config__setUseEmojiAsDefaultStyle1 = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat_Config__setUseEmojiAsDefaultStyle1( + jobject self_, + uint8_t useEmojiAsDefaultStyle, + jobject emojiAsDefaultStyleExceptions) { + load_env(); + load_class_global_ref(&_c_EmojiCompat_Config, + "androidx/emoji2/text/EmojiCompat$Config"); + if (_c_EmojiCompat_Config == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat_Config, + &_m_EmojiCompat_Config__setUseEmojiAsDefaultStyle1, + "setUseEmojiAsDefaultStyle", + "(ZLjava/util/List;)Landroidx/emoji2/text/EmojiCompat$Config;"); + if (_m_EmojiCompat_Config__setUseEmojiAsDefaultStyle1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_EmojiCompat_Config__setUseEmojiAsDefaultStyle1, + useEmojiAsDefaultStyle, emojiAsDefaultStyleExceptions); + return to_global_ref_result(_result); +} + +jmethodID _m_EmojiCompat_Config__setEmojiSpanIndicatorEnabled = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat_Config__setEmojiSpanIndicatorEnabled( + jobject self_, + uint8_t emojiSpanIndicatorEnabled) { + load_env(); + load_class_global_ref(&_c_EmojiCompat_Config, + "androidx/emoji2/text/EmojiCompat$Config"); + if (_c_EmojiCompat_Config == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat_Config, + &_m_EmojiCompat_Config__setEmojiSpanIndicatorEnabled, + "setEmojiSpanIndicatorEnabled", + "(Z)Landroidx/emoji2/text/EmojiCompat$Config;"); + if (_m_EmojiCompat_Config__setEmojiSpanIndicatorEnabled == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_EmojiCompat_Config__setEmojiSpanIndicatorEnabled, + emojiSpanIndicatorEnabled); + return to_global_ref_result(_result); +} + +jmethodID _m_EmojiCompat_Config__setEmojiSpanIndicatorColor = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat_Config__setEmojiSpanIndicatorColor(jobject self_, + int32_t color) { + load_env(); + load_class_global_ref(&_c_EmojiCompat_Config, + "androidx/emoji2/text/EmojiCompat$Config"); + if (_c_EmojiCompat_Config == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat_Config, + &_m_EmojiCompat_Config__setEmojiSpanIndicatorColor, + "setEmojiSpanIndicatorColor", + "(I)Landroidx/emoji2/text/EmojiCompat$Config;"); + if (_m_EmojiCompat_Config__setEmojiSpanIndicatorColor == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_EmojiCompat_Config__setEmojiSpanIndicatorColor, color); + return to_global_ref_result(_result); +} + +jmethodID _m_EmojiCompat_Config__setMetadataLoadStrategy = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat_Config__setMetadataLoadStrategy(jobject self_, + int32_t strategy) { + load_env(); + load_class_global_ref(&_c_EmojiCompat_Config, + "androidx/emoji2/text/EmojiCompat$Config"); + if (_c_EmojiCompat_Config == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat_Config, + &_m_EmojiCompat_Config__setMetadataLoadStrategy, + "setMetadataLoadStrategy", + "(I)Landroidx/emoji2/text/EmojiCompat$Config;"); + if (_m_EmojiCompat_Config__setMetadataLoadStrategy == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_EmojiCompat_Config__setMetadataLoadStrategy, strategy); + return to_global_ref_result(_result); +} + +jmethodID _m_EmojiCompat_Config__setSpanFactory = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat_Config__setSpanFactory(jobject self_, jobject factory) { + load_env(); + load_class_global_ref(&_c_EmojiCompat_Config, + "androidx/emoji2/text/EmojiCompat$Config"); + if (_c_EmojiCompat_Config == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat_Config, &_m_EmojiCompat_Config__setSpanFactory, + "setSpanFactory", + "(Landroidx/emoji2/text/EmojiCompat$SpanFactory;)Landroidx/" + "emoji2/text/EmojiCompat$Config;"); + if (_m_EmojiCompat_Config__setSpanFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_EmojiCompat_Config__setSpanFactory, factory); + return to_global_ref_result(_result); +} + +jmethodID _m_EmojiCompat_Config__setGlyphChecker = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat_Config__setGlyphChecker(jobject self_, + jobject glyphChecker) { + load_env(); + load_class_global_ref(&_c_EmojiCompat_Config, + "androidx/emoji2/text/EmojiCompat$Config"); + if (_c_EmojiCompat_Config == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat_Config, &_m_EmojiCompat_Config__setGlyphChecker, + "setGlyphChecker", + "(Landroidx/emoji2/text/EmojiCompat$GlyphChecker;)Landroidx/" + "emoji2/text/EmojiCompat$Config;"); + if (_m_EmojiCompat_Config__setGlyphChecker == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_EmojiCompat_Config__setGlyphChecker, glyphChecker); + return to_global_ref_result(_result); +} + +jmethodID _m_EmojiCompat_Config__getMetadataRepoLoader = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat_Config__getMetadataRepoLoader(jobject self_) { + load_env(); + load_class_global_ref(&_c_EmojiCompat_Config, + "androidx/emoji2/text/EmojiCompat$Config"); + if (_c_EmojiCompat_Config == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat_Config, + &_m_EmojiCompat_Config__getMetadataRepoLoader, + "getMetadataRepoLoader", + "()Landroidx/emoji2/text/EmojiCompat$MetadataRepoLoader;"); + if (_m_EmojiCompat_Config__getMetadataRepoLoader == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_EmojiCompat_Config__getMetadataRepoLoader); + return to_global_ref_result(_result); +} + +// androidx.emoji2.text.EmojiCompat$MetadataRepoLoaderCallback +jclass _c_EmojiCompat_MetadataRepoLoaderCallback = NULL; + +jmethodID _m_EmojiCompat_MetadataRepoLoaderCallback__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat_MetadataRepoLoaderCallback__new0() { + load_env(); + load_class_global_ref( + &_c_EmojiCompat_MetadataRepoLoaderCallback, + "androidx/emoji2/text/EmojiCompat$MetadataRepoLoaderCallback"); + if (_c_EmojiCompat_MetadataRepoLoaderCallback == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat_MetadataRepoLoaderCallback, + &_m_EmojiCompat_MetadataRepoLoaderCallback__new0, "", + "()V"); + if (_m_EmojiCompat_MetadataRepoLoaderCallback__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->NewObject(jniEnv, _c_EmojiCompat_MetadataRepoLoaderCallback, + _m_EmojiCompat_MetadataRepoLoaderCallback__new0); + return to_global_ref_result(_result); +} + +jmethodID _m_EmojiCompat_MetadataRepoLoaderCallback__onLoaded = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat_MetadataRepoLoaderCallback__onLoaded( + jobject self_, + jobject metadataRepo) { + load_env(); + load_class_global_ref( + &_c_EmojiCompat_MetadataRepoLoaderCallback, + "androidx/emoji2/text/EmojiCompat$MetadataRepoLoaderCallback"); + if (_c_EmojiCompat_MetadataRepoLoaderCallback == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat_MetadataRepoLoaderCallback, + &_m_EmojiCompat_MetadataRepoLoaderCallback__onLoaded, "onLoaded", + "(Landroidx/emoji2/text/MetadataRepo;)V"); + if (_m_EmojiCompat_MetadataRepoLoaderCallback__onLoaded == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, + _m_EmojiCompat_MetadataRepoLoaderCallback__onLoaded, + metadataRepo); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_EmojiCompat_MetadataRepoLoaderCallback__onFailed = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat_MetadataRepoLoaderCallback__onFailed(jobject self_, + jobject throwable) { + load_env(); + load_class_global_ref( + &_c_EmojiCompat_MetadataRepoLoaderCallback, + "androidx/emoji2/text/EmojiCompat$MetadataRepoLoaderCallback"); + if (_c_EmojiCompat_MetadataRepoLoaderCallback == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat_MetadataRepoLoaderCallback, + &_m_EmojiCompat_MetadataRepoLoaderCallback__onFailed, "onFailed", + "(Ljava/lang/Throwable;)V"); + if (_m_EmojiCompat_MetadataRepoLoaderCallback__onFailed == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, + _m_EmojiCompat_MetadataRepoLoaderCallback__onFailed, + throwable); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +// androidx.emoji2.text.EmojiCompat$GlyphChecker +jclass _c_EmojiCompat_GlyphChecker = NULL; + +jmethodID _m_EmojiCompat_GlyphChecker__hasGlyph = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat_GlyphChecker__hasGlyph(jobject self_, + jobject charSequence, + int32_t start, + int32_t end, + int32_t sdkAdded) { + load_env(); + load_class_global_ref(&_c_EmojiCompat_GlyphChecker, + "androidx/emoji2/text/EmojiCompat$GlyphChecker"); + if (_c_EmojiCompat_GlyphChecker == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat_GlyphChecker, + &_m_EmojiCompat_GlyphChecker__hasGlyph, "hasGlyph", + "(Ljava/lang/CharSequence;III)Z"); + if (_m_EmojiCompat_GlyphChecker__hasGlyph == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod( + jniEnv, self_, _m_EmojiCompat_GlyphChecker__hasGlyph, charSequence, start, + end, sdkAdded); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +// androidx.emoji2.text.EmojiCompat$MetadataRepoLoader +jclass _c_EmojiCompat_MetadataRepoLoader = NULL; + +jmethodID _m_EmojiCompat_MetadataRepoLoader__load = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat_MetadataRepoLoader__load(jobject self_, + jobject loaderCallback) { + load_env(); + load_class_global_ref(&_c_EmojiCompat_MetadataRepoLoader, + "androidx/emoji2/text/EmojiCompat$MetadataRepoLoader"); + if (_c_EmojiCompat_MetadataRepoLoader == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method( + _c_EmojiCompat_MetadataRepoLoader, + &_m_EmojiCompat_MetadataRepoLoader__load, "load", + "(Landroidx/emoji2/text/EmojiCompat$MetadataRepoLoaderCallback;)V"); + if (_m_EmojiCompat_MetadataRepoLoader__load == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod( + jniEnv, self_, _m_EmojiCompat_MetadataRepoLoader__load, loaderCallback); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +// androidx.emoji2.text.EmojiCompat$InitCallback +jclass _c_EmojiCompat_InitCallback = NULL; + +jmethodID _m_EmojiCompat_InitCallback__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat_InitCallback__new0() { + load_env(); + load_class_global_ref(&_c_EmojiCompat_InitCallback, + "androidx/emoji2/text/EmojiCompat$InitCallback"); + if (_c_EmojiCompat_InitCallback == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat_InitCallback, &_m_EmojiCompat_InitCallback__new0, + "", "()V"); + if (_m_EmojiCompat_InitCallback__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject(jniEnv, _c_EmojiCompat_InitCallback, + _m_EmojiCompat_InitCallback__new0); + return to_global_ref_result(_result); +} + +jmethodID _m_EmojiCompat_InitCallback__onInitialized = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat_InitCallback__onInitialized(jobject self_) { + load_env(); + load_class_global_ref(&_c_EmojiCompat_InitCallback, + "androidx/emoji2/text/EmojiCompat$InitCallback"); + if (_c_EmojiCompat_InitCallback == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat_InitCallback, + &_m_EmojiCompat_InitCallback__onInitialized, "onInitialized", + "()V"); + if (_m_EmojiCompat_InitCallback__onInitialized == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, + _m_EmojiCompat_InitCallback__onInitialized); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_EmojiCompat_InitCallback__onFailed = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat_InitCallback__onFailed(jobject self_, jobject throwable) { + load_env(); + load_class_global_ref(&_c_EmojiCompat_InitCallback, + "androidx/emoji2/text/EmojiCompat$InitCallback"); + if (_c_EmojiCompat_InitCallback == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat_InitCallback, + &_m_EmojiCompat_InitCallback__onFailed, "onFailed", + "(Ljava/lang/Throwable;)V"); + if (_m_EmojiCompat_InitCallback__onFailed == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, + _m_EmojiCompat_InitCallback__onFailed, throwable); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +// androidx.emoji2.text.EmojiCompat$DefaultSpanFactory +jclass _c_EmojiCompat_DefaultSpanFactory = NULL; + +jmethodID _m_EmojiCompat_DefaultSpanFactory__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat_DefaultSpanFactory__new0() { + load_env(); + load_class_global_ref(&_c_EmojiCompat_DefaultSpanFactory, + "androidx/emoji2/text/EmojiCompat$DefaultSpanFactory"); + if (_c_EmojiCompat_DefaultSpanFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat_DefaultSpanFactory, + &_m_EmojiCompat_DefaultSpanFactory__new0, "", "()V"); + if (_m_EmojiCompat_DefaultSpanFactory__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->NewObject(jniEnv, _c_EmojiCompat_DefaultSpanFactory, + _m_EmojiCompat_DefaultSpanFactory__new0); + return to_global_ref_result(_result); +} + +jmethodID _m_EmojiCompat_DefaultSpanFactory__createSpan = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat_DefaultSpanFactory__createSpan(jobject self_, + jobject rasterizer) { + load_env(); + load_class_global_ref(&_c_EmojiCompat_DefaultSpanFactory, + "androidx/emoji2/text/EmojiCompat$DefaultSpanFactory"); + if (_c_EmojiCompat_DefaultSpanFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat_DefaultSpanFactory, + &_m_EmojiCompat_DefaultSpanFactory__createSpan, "createSpan", + "(Landroidx/emoji2/text/TypefaceEmojiRasterizer;)Landroidx/" + "emoji2/text/EmojiSpan;"); + if (_m_EmojiCompat_DefaultSpanFactory__createSpan == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_EmojiCompat_DefaultSpanFactory__createSpan, rasterizer); + return to_global_ref_result(_result); +} + +// androidx.emoji2.text.EmojiCompat$SpanFactory +jclass _c_EmojiCompat_SpanFactory = NULL; + +jmethodID _m_EmojiCompat_SpanFactory__createSpan = NULL; +FFI_PLUGIN_EXPORT +JniResult EmojiCompat_SpanFactory__createSpan(jobject self_, + jobject rasterizer) { + load_env(); + load_class_global_ref(&_c_EmojiCompat_SpanFactory, + "androidx/emoji2/text/EmojiCompat$SpanFactory"); + if (_c_EmojiCompat_SpanFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_EmojiCompat_SpanFactory, + &_m_EmojiCompat_SpanFactory__createSpan, "createSpan", + "(Landroidx/emoji2/text/TypefaceEmojiRasterizer;)Landroidx/" + "emoji2/text/EmojiSpan;"); + if (_m_EmojiCompat_SpanFactory__createSpan == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_EmojiCompat_SpanFactory__createSpan, rasterizer); + return to_global_ref_result(_result); +} + +// androidx.emoji2.text.DefaultEmojiCompatConfig +jclass _c_DefaultEmojiCompatConfig = NULL; + +jmethodID _m_DefaultEmojiCompatConfig__create = NULL; +FFI_PLUGIN_EXPORT +JniResult DefaultEmojiCompatConfig__create(jobject context) { + load_env(); + load_class_global_ref(&_c_DefaultEmojiCompatConfig, + "androidx/emoji2/text/DefaultEmojiCompatConfig"); + if (_c_DefaultEmojiCompatConfig == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_DefaultEmojiCompatConfig, + &_m_DefaultEmojiCompatConfig__create, "create", + "(Landroid/content/Context;)Landroidx/emoji2/text/" + "FontRequestEmojiCompatConfig;"); + if (_m_DefaultEmojiCompatConfig__create == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_DefaultEmojiCompatConfig, _m_DefaultEmojiCompatConfig__create, + context); + return to_global_ref_result(_result); +} + +// androidx.emoji2.text.DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper_API28 +jclass _c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28 = NULL; + +jmethodID + _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28__new0 = + NULL; +FFI_PLUGIN_EXPORT +JniResult +DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28__new0() { + load_env(); + load_class_global_ref( + &_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28, + "androidx/emoji2/text/" + "DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper_API28"); + if (_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method( + _c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28, + &_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28__new0, + "", "()V"); + if (_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28__new0 == + NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject( + jniEnv, _c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28, + _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28__new0); + return to_global_ref_result(_result); +} + +jmethodID + _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28__getSigningSignatures1 = + NULL; +FFI_PLUGIN_EXPORT +JniResult +DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28__getSigningSignatures1( + jobject self_, + jobject packageManager, + jobject providerPackage) { + load_env(); + load_class_global_ref( + &_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28, + "androidx/emoji2/text/" + "DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper_API28"); + if (_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method( + _c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28, + &_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28__getSigningSignatures1, + "getSigningSignatures", + "(Landroid/content/pm/PackageManager;Ljava/lang/String;)[Landroid/" + "content/pm/Signature;"); + if (_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28__getSigningSignatures1 == + NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, + _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API28__getSigningSignatures1, + packageManager, providerPackage); + return to_global_ref_result(_result); +} + +// androidx.emoji2.text.DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper_API19 +jclass _c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19 = NULL; + +jmethodID + _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19__new0 = + NULL; +FFI_PLUGIN_EXPORT +JniResult +DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19__new0() { + load_env(); + load_class_global_ref( + &_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19, + "androidx/emoji2/text/" + "DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper_API19"); + if (_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method( + _c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19, + &_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19__new0, + "", "()V"); + if (_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19__new0 == + NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject( + jniEnv, _c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19, + _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19__new0); + return to_global_ref_result(_result); +} + +jmethodID + _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19__queryIntentContentProviders = + NULL; +FFI_PLUGIN_EXPORT +JniResult +DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19__queryIntentContentProviders( + jobject self_, + jobject packageManager, + jobject intent, + int32_t flags) { + load_env(); + load_class_global_ref( + &_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19, + "androidx/emoji2/text/" + "DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper_API19"); + if (_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method( + _c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19, + &_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19__queryIntentContentProviders, + "queryIntentContentProviders", + "(Landroid/content/pm/PackageManager;Landroid/content/Intent;I)Ljava/" + "util/List;"); + if (_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19__queryIntentContentProviders == + NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, + _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19__queryIntentContentProviders, + packageManager, intent, flags); + return to_global_ref_result(_result); +} + +jmethodID + _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19__getProviderInfo = + NULL; +FFI_PLUGIN_EXPORT +JniResult +DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19__getProviderInfo( + jobject self_, + jobject resolveInfo) { + load_env(); + load_class_global_ref( + &_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19, + "androidx/emoji2/text/" + "DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper_API19"); + if (_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method( + _c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19, + &_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19__getProviderInfo, + "getProviderInfo", + "(Landroid/content/pm/ResolveInfo;)Landroid/content/pm/ProviderInfo;"); + if (_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19__getProviderInfo == + NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, + _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper_API19__getProviderInfo, + resolveInfo); + return to_global_ref_result(_result); +} + +// androidx.emoji2.text.DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper +jclass _c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper = NULL; + +jmethodID _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__new0 = + NULL; +FFI_PLUGIN_EXPORT +JniResult DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__new0() { + load_env(); + load_class_global_ref( + &_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper, + "androidx/emoji2/text/" + "DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper"); + if (_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper, + &_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__new0, + "", "()V"); + if (_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject( + jniEnv, _c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper, + _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__new0); + return to_global_ref_result(_result); +} + +jmethodID + _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__getSigningSignatures = + NULL; +FFI_PLUGIN_EXPORT +JniResult +DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__getSigningSignatures( + jobject self_, + jobject packageManager, + jobject providerPackage) { + load_env(); + load_class_global_ref( + &_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper, + "androidx/emoji2/text/" + "DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper"); + if (_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method( + _c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper, + &_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__getSigningSignatures, + "getSigningSignatures", + "(Landroid/content/pm/PackageManager;Ljava/lang/String;)[Landroid/" + "content/pm/Signature;"); + if (_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__getSigningSignatures == + NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, + _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__getSigningSignatures, + packageManager, providerPackage); + return to_global_ref_result(_result); +} + +jmethodID + _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__queryIntentContentProviders = + NULL; +FFI_PLUGIN_EXPORT +JniResult +DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__queryIntentContentProviders( + jobject self_, + jobject packageManager, + jobject intent, + int32_t flags) { + load_env(); + load_class_global_ref( + &_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper, + "androidx/emoji2/text/" + "DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper"); + if (_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method( + _c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper, + &_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__queryIntentContentProviders, + "queryIntentContentProviders", + "(Landroid/content/pm/PackageManager;Landroid/content/Intent;I)Ljava/" + "util/List;"); + if (_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__queryIntentContentProviders == + NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, + _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__queryIntentContentProviders, + packageManager, intent, flags); + return to_global_ref_result(_result); +} + +jmethodID + _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__getProviderInfo = + NULL; +FFI_PLUGIN_EXPORT +JniResult +DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__getProviderInfo( + jobject self_, + jobject resolveInfo) { + load_env(); + load_class_global_ref( + &_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper, + "androidx/emoji2/text/" + "DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper"); + if (_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method( + _c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper, + &_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__getProviderInfo, + "getProviderInfo", + "(Landroid/content/pm/ResolveInfo;)Landroid/content/pm/ProviderInfo;"); + if (_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__getProviderInfo == + NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, + _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigHelper__getProviderInfo, + resolveInfo); + return to_global_ref_result(_result); +} + +// androidx.emoji2.text.DefaultEmojiCompatConfig$DefaultEmojiCompatConfigFactory +jclass _c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory = NULL; + +jmethodID _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory__new0 = + NULL; +FFI_PLUGIN_EXPORT +JniResult DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory__new0( + jobject helper) { + load_env(); + load_class_global_ref( + &_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory, + "androidx/emoji2/text/" + "DefaultEmojiCompatConfig$DefaultEmojiCompatConfigFactory"); + if (_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method( + _c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory, + &_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory__new0, + "", + "(Landroidx/emoji2/text/" + "DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper;)V"); + if (_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject( + jniEnv, _c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory, + _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory__new0, + helper); + return to_global_ref_result(_result); +} + +jmethodID _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory__create = + NULL; +FFI_PLUGIN_EXPORT +JniResult DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory__create( + jobject self_, + jobject context) { + load_env(); + load_class_global_ref( + &_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory, + "androidx/emoji2/text/" + "DefaultEmojiCompatConfig$DefaultEmojiCompatConfigFactory"); + if (_c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method( + _c_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory, + &_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory__create, + "create", + "(Landroid/content/Context;)Landroidx/emoji2/text/EmojiCompat$Config;"); + if (_m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory__create == + NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, + _m_DefaultEmojiCompatConfig_DefaultEmojiCompatConfigFactory__create, + context); + return to_global_ref_result(_result); +} + +// android.os.Build$Partition +jclass _c_Build_Partition = NULL; + +jmethodID _m_Build_Partition__getName = NULL; +FFI_PLUGIN_EXPORT +JniResult Build_Partition__getName(jobject self_) { + load_env(); + load_class_global_ref(&_c_Build_Partition, "android/os/Build$Partition"); + if (_c_Build_Partition == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Build_Partition, &_m_Build_Partition__getName, "getName", + "()Ljava/lang/String;"); + if (_m_Build_Partition__getName == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_Build_Partition__getName); + return to_global_ref_result(_result); +} + +jmethodID _m_Build_Partition__getFingerprint = NULL; +FFI_PLUGIN_EXPORT +JniResult Build_Partition__getFingerprint(jobject self_) { + load_env(); + load_class_global_ref(&_c_Build_Partition, "android/os/Build$Partition"); + if (_c_Build_Partition == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Build_Partition, &_m_Build_Partition__getFingerprint, + "getFingerprint", "()Ljava/lang/String;"); + if (_m_Build_Partition__getFingerprint == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_Build_Partition__getFingerprint); + return to_global_ref_result(_result); +} + +jmethodID _m_Build_Partition__getBuildTimeMillis = NULL; +FFI_PLUGIN_EXPORT +JniResult Build_Partition__getBuildTimeMillis(jobject self_) { + load_env(); + load_class_global_ref(&_c_Build_Partition, "android/os/Build$Partition"); + if (_c_Build_Partition == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Build_Partition, &_m_Build_Partition__getBuildTimeMillis, + "getBuildTimeMillis", "()J"); + if (_m_Build_Partition__getBuildTimeMillis == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int64_t _result = (*jniEnv)->CallLongMethod( + jniEnv, self_, _m_Build_Partition__getBuildTimeMillis); + return (JniResult){.value = {.j = _result}, .exception = check_exception()}; +} + +jmethodID _m_Build_Partition__equals1 = NULL; +FFI_PLUGIN_EXPORT +JniResult Build_Partition__equals1(jobject self_, jobject object) { + load_env(); + load_class_global_ref(&_c_Build_Partition, "android/os/Build$Partition"); + if (_c_Build_Partition == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Build_Partition, &_m_Build_Partition__equals1, "equals", + "(Ljava/lang/Object;)Z"); + if (_m_Build_Partition__equals1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod( + jniEnv, self_, _m_Build_Partition__equals1, object); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_Build_Partition__hashCode1 = NULL; +FFI_PLUGIN_EXPORT +JniResult Build_Partition__hashCode1(jobject self_) { + load_env(); + load_class_global_ref(&_c_Build_Partition, "android/os/Build$Partition"); + if (_c_Build_Partition == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Build_Partition, &_m_Build_Partition__hashCode1, "hashCode", + "()I"); + if (_m_Build_Partition__hashCode1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = + (*jniEnv)->CallIntMethod(jniEnv, self_, _m_Build_Partition__hashCode1); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +// android.os.Build$VERSION +jclass _c_Build_VERSION = NULL; + +jmethodID _m_Build_VERSION__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult Build_VERSION__new0() { + load_env(); + load_class_global_ref(&_c_Build_VERSION, "android/os/Build$VERSION"); + if (_c_Build_VERSION == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Build_VERSION, &_m_Build_VERSION__new0, "", "()V"); + if (_m_Build_VERSION__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->NewObject(jniEnv, _c_Build_VERSION, _m_Build_VERSION__new0); + return to_global_ref_result(_result); +} + +jfieldID _f_Build_VERSION__BASE_OS = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build_VERSION__BASE_OS() { + load_env(); + load_class_global_ref(&_c_Build_VERSION, "android/os/Build$VERSION"); + if (_c_Build_VERSION == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build_VERSION, &_f_Build_VERSION__BASE_OS, "BASE_OS", + "Ljava/lang/String;"); + jobject _result = (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build_VERSION, + _f_Build_VERSION__BASE_OS); + return to_global_ref_result(_result); +} + +jfieldID _f_Build_VERSION__CODENAME = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build_VERSION__CODENAME() { + load_env(); + load_class_global_ref(&_c_Build_VERSION, "android/os/Build$VERSION"); + if (_c_Build_VERSION == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build_VERSION, &_f_Build_VERSION__CODENAME, "CODENAME", + "Ljava/lang/String;"); + jobject _result = (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build_VERSION, + _f_Build_VERSION__CODENAME); + return to_global_ref_result(_result); +} + +jfieldID _f_Build_VERSION__INCREMENTAL = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build_VERSION__INCREMENTAL() { + load_env(); + load_class_global_ref(&_c_Build_VERSION, "android/os/Build$VERSION"); + if (_c_Build_VERSION == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build_VERSION, &_f_Build_VERSION__INCREMENTAL, + "INCREMENTAL", "Ljava/lang/String;"); + jobject _result = (*jniEnv)->GetStaticObjectField( + jniEnv, _c_Build_VERSION, _f_Build_VERSION__INCREMENTAL); + return to_global_ref_result(_result); +} + +jfieldID _f_Build_VERSION__MEDIA_PERFORMANCE_CLASS = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build_VERSION__MEDIA_PERFORMANCE_CLASS() { + load_env(); + load_class_global_ref(&_c_Build_VERSION, "android/os/Build$VERSION"); + if (_c_Build_VERSION == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build_VERSION, + &_f_Build_VERSION__MEDIA_PERFORMANCE_CLASS, + "MEDIA_PERFORMANCE_CLASS", "I"); + int32_t _result = (*jniEnv)->GetStaticIntField( + jniEnv, _c_Build_VERSION, _f_Build_VERSION__MEDIA_PERFORMANCE_CLASS); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jfieldID _f_Build_VERSION__PREVIEW_SDK_INT = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build_VERSION__PREVIEW_SDK_INT() { + load_env(); + load_class_global_ref(&_c_Build_VERSION, "android/os/Build$VERSION"); + if (_c_Build_VERSION == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build_VERSION, &_f_Build_VERSION__PREVIEW_SDK_INT, + "PREVIEW_SDK_INT", "I"); + int32_t _result = (*jniEnv)->GetStaticIntField( + jniEnv, _c_Build_VERSION, _f_Build_VERSION__PREVIEW_SDK_INT); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jfieldID _f_Build_VERSION__RELEASE = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build_VERSION__RELEASE() { + load_env(); + load_class_global_ref(&_c_Build_VERSION, "android/os/Build$VERSION"); + if (_c_Build_VERSION == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build_VERSION, &_f_Build_VERSION__RELEASE, "RELEASE", + "Ljava/lang/String;"); + jobject _result = (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build_VERSION, + _f_Build_VERSION__RELEASE); + return to_global_ref_result(_result); +} + +jfieldID _f_Build_VERSION__RELEASE_OR_CODENAME = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build_VERSION__RELEASE_OR_CODENAME() { + load_env(); + load_class_global_ref(&_c_Build_VERSION, "android/os/Build$VERSION"); + if (_c_Build_VERSION == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build_VERSION, &_f_Build_VERSION__RELEASE_OR_CODENAME, + "RELEASE_OR_CODENAME", "Ljava/lang/String;"); + jobject _result = (*jniEnv)->GetStaticObjectField( + jniEnv, _c_Build_VERSION, _f_Build_VERSION__RELEASE_OR_CODENAME); + return to_global_ref_result(_result); +} + +jfieldID _f_Build_VERSION__RELEASE_OR_PREVIEW_DISPLAY = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build_VERSION__RELEASE_OR_PREVIEW_DISPLAY() { + load_env(); + load_class_global_ref(&_c_Build_VERSION, "android/os/Build$VERSION"); + if (_c_Build_VERSION == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build_VERSION, + &_f_Build_VERSION__RELEASE_OR_PREVIEW_DISPLAY, + "RELEASE_OR_PREVIEW_DISPLAY", "Ljava/lang/String;"); + jobject _result = (*jniEnv)->GetStaticObjectField( + jniEnv, _c_Build_VERSION, _f_Build_VERSION__RELEASE_OR_PREVIEW_DISPLAY); + return to_global_ref_result(_result); +} + +jfieldID _f_Build_VERSION__SDK = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build_VERSION__SDK() { + load_env(); + load_class_global_ref(&_c_Build_VERSION, "android/os/Build$VERSION"); + if (_c_Build_VERSION == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build_VERSION, &_f_Build_VERSION__SDK, "SDK", + "Ljava/lang/String;"); + jobject _result = (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build_VERSION, + _f_Build_VERSION__SDK); + return to_global_ref_result(_result); +} + +jfieldID _f_Build_VERSION__SDK_INT = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build_VERSION__SDK_INT() { + load_env(); + load_class_global_ref(&_c_Build_VERSION, "android/os/Build$VERSION"); + if (_c_Build_VERSION == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build_VERSION, &_f_Build_VERSION__SDK_INT, "SDK_INT", + "I"); + int32_t _result = (*jniEnv)->GetStaticIntField(jniEnv, _c_Build_VERSION, + _f_Build_VERSION__SDK_INT); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jfieldID _f_Build_VERSION__SECURITY_PATCH = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build_VERSION__SECURITY_PATCH() { + load_env(); + load_class_global_ref(&_c_Build_VERSION, "android/os/Build$VERSION"); + if (_c_Build_VERSION == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build_VERSION, &_f_Build_VERSION__SECURITY_PATCH, + "SECURITY_PATCH", "Ljava/lang/String;"); + jobject _result = (*jniEnv)->GetStaticObjectField( + jniEnv, _c_Build_VERSION, _f_Build_VERSION__SECURITY_PATCH); + return to_global_ref_result(_result); +} + +// android.os.Build$VERSION_CODES +jclass _c_Build_VERSION_CODES = NULL; + +jmethodID _m_Build_VERSION_CODES__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult Build_VERSION_CODES__new0() { + load_env(); + load_class_global_ref(&_c_Build_VERSION_CODES, + "android/os/Build$VERSION_CODES"); + if (_c_Build_VERSION_CODES == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Build_VERSION_CODES, &_m_Build_VERSION_CODES__new0, "", + "()V"); + if (_m_Build_VERSION_CODES__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject(jniEnv, _c_Build_VERSION_CODES, + _m_Build_VERSION_CODES__new0); + return to_global_ref_result(_result); +} + +// android.os.Build +jclass _c_Build = NULL; + +jmethodID _m_Build__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult Build__new0() { + load_env(); + load_class_global_ref(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Build, &_m_Build__new0, "", "()V"); + if (_m_Build__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject(jniEnv, _c_Build, _m_Build__new0); + return to_global_ref_result(_result); +} + +jmethodID _m_Build__getSerial = NULL; +FFI_PLUGIN_EXPORT +JniResult Build__getSerial() { + load_env(); + load_class_global_ref(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_Build, &_m_Build__getSerial, "getSerial", + "()Ljava/lang/String;"); + if (_m_Build__getSerial == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallStaticObjectMethod(jniEnv, _c_Build, _m_Build__getSerial); + return to_global_ref_result(_result); +} + +jmethodID _m_Build__getFingerprintedPartitions = NULL; +FFI_PLUGIN_EXPORT +JniResult Build__getFingerprintedPartitions() { + load_env(); + load_class_global_ref(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_Build, &_m_Build__getFingerprintedPartitions, + "getFingerprintedPartitions", "()Ljava/util/List;"); + if (_m_Build__getFingerprintedPartitions == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_Build, _m_Build__getFingerprintedPartitions); + return to_global_ref_result(_result); +} + +jmethodID _m_Build__getRadioVersion = NULL; +FFI_PLUGIN_EXPORT +JniResult Build__getRadioVersion() { + load_env(); + load_class_global_ref(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_Build, &_m_Build__getRadioVersion, "getRadioVersion", + "()Ljava/lang/String;"); + if (_m_Build__getRadioVersion == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_Build, _m_Build__getRadioVersion); + return to_global_ref_result(_result); +} + +jfieldID _f_Build__BOARD = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__BOARD() { + load_env(); + load_class_global_ref(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__BOARD, "BOARD", "Ljava/lang/String;"); + jobject _result = + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__BOARD); + return to_global_ref_result(_result); +} + +jfieldID _f_Build__BOOTLOADER = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__BOOTLOADER() { + load_env(); + load_class_global_ref(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__BOOTLOADER, "BOOTLOADER", + "Ljava/lang/String;"); + jobject _result = + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__BOOTLOADER); + return to_global_ref_result(_result); +} + +jfieldID _f_Build__BRAND = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__BRAND() { + load_env(); + load_class_global_ref(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__BRAND, "BRAND", "Ljava/lang/String;"); + jobject _result = + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__BRAND); + return to_global_ref_result(_result); +} + +jfieldID _f_Build__CPU_ABI = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__CPU_ABI() { + load_env(); + load_class_global_ref(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__CPU_ABI, "CPU_ABI", + "Ljava/lang/String;"); + jobject _result = + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__CPU_ABI); + return to_global_ref_result(_result); +} + +jfieldID _f_Build__CPU_ABI2 = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__CPU_ABI2() { + load_env(); + load_class_global_ref(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__CPU_ABI2, "CPU_ABI2", + "Ljava/lang/String;"); + jobject _result = + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__CPU_ABI2); + return to_global_ref_result(_result); +} + +jfieldID _f_Build__DEVICE = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__DEVICE() { + load_env(); + load_class_global_ref(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__DEVICE, "DEVICE", + "Ljava/lang/String;"); + jobject _result = + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__DEVICE); + return to_global_ref_result(_result); +} + +jfieldID _f_Build__DISPLAY = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__DISPLAY() { + load_env(); + load_class_global_ref(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__DISPLAY, "DISPLAY", + "Ljava/lang/String;"); + jobject _result = + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__DISPLAY); + return to_global_ref_result(_result); +} + +jfieldID _f_Build__FINGERPRINT = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__FINGERPRINT() { + load_env(); + load_class_global_ref(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__FINGERPRINT, "FINGERPRINT", + "Ljava/lang/String;"); + jobject _result = + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__FINGERPRINT); + return to_global_ref_result(_result); +} + +jfieldID _f_Build__HARDWARE = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__HARDWARE() { + load_env(); + load_class_global_ref(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__HARDWARE, "HARDWARE", + "Ljava/lang/String;"); + jobject _result = + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__HARDWARE); + return to_global_ref_result(_result); +} + +jfieldID _f_Build__HOST = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__HOST() { + load_env(); + load_class_global_ref(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__HOST, "HOST", "Ljava/lang/String;"); + jobject _result = + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__HOST); + return to_global_ref_result(_result); +} + +jfieldID _f_Build__ID = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__ID() { + load_env(); + load_class_global_ref(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__ID, "ID", "Ljava/lang/String;"); + jobject _result = + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__ID); + return to_global_ref_result(_result); +} + +jfieldID _f_Build__MANUFACTURER = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__MANUFACTURER() { + load_env(); + load_class_global_ref(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__MANUFACTURER, "MANUFACTURER", + "Ljava/lang/String;"); + jobject _result = + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__MANUFACTURER); + return to_global_ref_result(_result); +} + +jfieldID _f_Build__MODEL = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__MODEL() { + load_env(); + load_class_global_ref(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__MODEL, "MODEL", "Ljava/lang/String;"); + jobject _result = + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__MODEL); + return to_global_ref_result(_result); +} + +jfieldID _f_Build__ODM_SKU = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__ODM_SKU() { + load_env(); + load_class_global_ref(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__ODM_SKU, "ODM_SKU", + "Ljava/lang/String;"); + jobject _result = + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__ODM_SKU); + return to_global_ref_result(_result); +} + +jfieldID _f_Build__PRODUCT = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__PRODUCT() { + load_env(); + load_class_global_ref(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__PRODUCT, "PRODUCT", + "Ljava/lang/String;"); + jobject _result = + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__PRODUCT); + return to_global_ref_result(_result); +} + +jfieldID _f_Build__RADIO = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__RADIO() { + load_env(); + load_class_global_ref(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__RADIO, "RADIO", "Ljava/lang/String;"); + jobject _result = + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__RADIO); + return to_global_ref_result(_result); +} + +jfieldID _f_Build__SERIAL = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__SERIAL() { + load_env(); + load_class_global_ref(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__SERIAL, "SERIAL", + "Ljava/lang/String;"); + jobject _result = + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__SERIAL); + return to_global_ref_result(_result); +} + +jfieldID _f_Build__SKU = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__SKU() { + load_env(); + load_class_global_ref(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__SKU, "SKU", "Ljava/lang/String;"); + jobject _result = + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__SKU); + return to_global_ref_result(_result); +} + +jfieldID _f_Build__SOC_MANUFACTURER = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__SOC_MANUFACTURER() { + load_env(); + load_class_global_ref(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__SOC_MANUFACTURER, "SOC_MANUFACTURER", + "Ljava/lang/String;"); + jobject _result = (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, + _f_Build__SOC_MANUFACTURER); + return to_global_ref_result(_result); +} + +jfieldID _f_Build__SOC_MODEL = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__SOC_MODEL() { + load_env(); + load_class_global_ref(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__SOC_MODEL, "SOC_MODEL", + "Ljava/lang/String;"); + jobject _result = + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__SOC_MODEL); + return to_global_ref_result(_result); +} + +jfieldID _f_Build__SUPPORTED_32_BIT_ABIS = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__SUPPORTED_32_BIT_ABIS() { + load_env(); + load_class_global_ref(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.value = {.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 = (*jniEnv)->GetStaticObjectField( + jniEnv, _c_Build, _f_Build__SUPPORTED_32_BIT_ABIS); + return to_global_ref_result(_result); +} + +jfieldID _f_Build__SUPPORTED_64_BIT_ABIS = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__SUPPORTED_64_BIT_ABIS() { + load_env(); + load_class_global_ref(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.value = {.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 = (*jniEnv)->GetStaticObjectField( + jniEnv, _c_Build, _f_Build__SUPPORTED_64_BIT_ABIS); + return to_global_ref_result(_result); +} + +jfieldID _f_Build__SUPPORTED_ABIS = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__SUPPORTED_ABIS() { + load_env(); + load_class_global_ref(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__SUPPORTED_ABIS, "SUPPORTED_ABIS", + "[Ljava/lang/String;"); + jobject _result = (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, + _f_Build__SUPPORTED_ABIS); + return to_global_ref_result(_result); +} + +jfieldID _f_Build__TAGS = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__TAGS() { + load_env(); + load_class_global_ref(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__TAGS, "TAGS", "Ljava/lang/String;"); + jobject _result = + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__TAGS); + return to_global_ref_result(_result); +} + +jfieldID _f_Build__TIME = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__TIME() { + load_env(); + load_class_global_ref(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.value = {.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){.value = {.j = _result}, .exception = check_exception()}; +} + +jfieldID _f_Build__TYPE = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__TYPE() { + load_env(); + load_class_global_ref(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__TYPE, "TYPE", "Ljava/lang/String;"); + jobject _result = + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__TYPE); + return to_global_ref_result(_result); +} + +jfieldID _f_Build__USER = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__USER() { + load_env(); + load_class_global_ref(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__USER, "USER", "Ljava/lang/String;"); + jobject _result = + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__USER); + return to_global_ref_result(_result); +} + +// java.util.HashMap +jclass _c_HashMap = NULL; + +jmethodID _m_HashMap__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult HashMap__new0(int32_t i, float f) { + load_env(); + load_class_global_ref(&_c_HashMap, "java/util/HashMap"); + if (_c_HashMap == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_HashMap, &_m_HashMap__new0, "", "(IF)V"); + if (_m_HashMap__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->NewObject(jniEnv, _c_HashMap, _m_HashMap__new0, i, f); + return to_global_ref_result(_result); +} + +jmethodID _m_HashMap__new1 = NULL; +FFI_PLUGIN_EXPORT +JniResult HashMap__new1(int32_t i) { + load_env(); + load_class_global_ref(&_c_HashMap, "java/util/HashMap"); + if (_c_HashMap == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_HashMap, &_m_HashMap__new1, "", "(I)V"); + if (_m_HashMap__new1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->NewObject(jniEnv, _c_HashMap, _m_HashMap__new1, i); + return to_global_ref_result(_result); +} + +jmethodID _m_HashMap__new2 = NULL; +FFI_PLUGIN_EXPORT +JniResult HashMap__new2() { + load_env(); + load_class_global_ref(&_c_HashMap, "java/util/HashMap"); + if (_c_HashMap == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_HashMap, &_m_HashMap__new2, "", "()V"); + if (_m_HashMap__new2 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject(jniEnv, _c_HashMap, _m_HashMap__new2); + return to_global_ref_result(_result); +} + +jmethodID _m_HashMap__new3 = NULL; +FFI_PLUGIN_EXPORT +JniResult HashMap__new3(jobject map) { + load_env(); + load_class_global_ref(&_c_HashMap, "java/util/HashMap"); + if (_c_HashMap == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_HashMap, &_m_HashMap__new3, "", "(Ljava/util/Map;)V"); + if (_m_HashMap__new3 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->NewObject(jniEnv, _c_HashMap, _m_HashMap__new3, map); + return to_global_ref_result(_result); +} + +jmethodID _m_HashMap__size = NULL; +FFI_PLUGIN_EXPORT +JniResult HashMap__size(jobject self_) { + load_env(); + load_class_global_ref(&_c_HashMap, "java/util/HashMap"); + if (_c_HashMap == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_HashMap, &_m_HashMap__size, "size", "()I"); + if (_m_HashMap__size == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = (*jniEnv)->CallIntMethod(jniEnv, self_, _m_HashMap__size); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_HashMap__isEmpty = NULL; +FFI_PLUGIN_EXPORT +JniResult HashMap__isEmpty(jobject self_) { + load_env(); + load_class_global_ref(&_c_HashMap, "java/util/HashMap"); + if (_c_HashMap == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_HashMap, &_m_HashMap__isEmpty, "isEmpty", "()Z"); + if (_m_HashMap__isEmpty == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = + (*jniEnv)->CallBooleanMethod(jniEnv, self_, _m_HashMap__isEmpty); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_HashMap__get0 = NULL; +FFI_PLUGIN_EXPORT +JniResult HashMap__get0(jobject self_, jobject object) { + load_env(); + load_class_global_ref(&_c_HashMap, "java/util/HashMap"); + if (_c_HashMap == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_HashMap, &_m_HashMap__get0, "get", + "(Ljava/lang/Object;)Ljava/lang/Object;"); + if (_m_HashMap__get0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_HashMap__get0, object); + return to_global_ref_result(_result); +} + +jmethodID _m_HashMap__containsKey = NULL; +FFI_PLUGIN_EXPORT +JniResult HashMap__containsKey(jobject self_, jobject object) { + load_env(); + load_class_global_ref(&_c_HashMap, "java/util/HashMap"); + if (_c_HashMap == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_HashMap, &_m_HashMap__containsKey, "containsKey", + "(Ljava/lang/Object;)Z"); + if (_m_HashMap__containsKey == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod( + jniEnv, self_, _m_HashMap__containsKey, object); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_HashMap__put = NULL; +FFI_PLUGIN_EXPORT +JniResult HashMap__put(jobject self_, jobject object, jobject object1) { + load_env(); + load_class_global_ref(&_c_HashMap, "java/util/HashMap"); + if (_c_HashMap == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_HashMap, &_m_HashMap__put, "put", + "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); + if (_m_HashMap__put == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_HashMap__put, + object, object1); + return to_global_ref_result(_result); +} + +jmethodID _m_HashMap__putAll = NULL; +FFI_PLUGIN_EXPORT +JniResult HashMap__putAll(jobject self_, jobject map) { + load_env(); + load_class_global_ref(&_c_HashMap, "java/util/HashMap"); + if (_c_HashMap == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_HashMap, &_m_HashMap__putAll, "putAll", "(Ljava/util/Map;)V"); + if (_m_HashMap__putAll == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_HashMap__putAll, map); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_HashMap__remove = NULL; +FFI_PLUGIN_EXPORT +JniResult HashMap__remove(jobject self_, jobject object) { + load_env(); + load_class_global_ref(&_c_HashMap, "java/util/HashMap"); + if (_c_HashMap == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_HashMap, &_m_HashMap__remove, "remove", + "(Ljava/lang/Object;)Ljava/lang/Object;"); + if (_m_HashMap__remove == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_HashMap__remove, object); + return to_global_ref_result(_result); +} + +jmethodID _m_HashMap__clear = NULL; +FFI_PLUGIN_EXPORT +JniResult HashMap__clear(jobject self_) { + load_env(); + load_class_global_ref(&_c_HashMap, "java/util/HashMap"); + if (_c_HashMap == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_HashMap, &_m_HashMap__clear, "clear", "()V"); + if (_m_HashMap__clear == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_HashMap__clear); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_HashMap__containsValue = NULL; +FFI_PLUGIN_EXPORT +JniResult HashMap__containsValue(jobject self_, jobject object) { + load_env(); + load_class_global_ref(&_c_HashMap, "java/util/HashMap"); + if (_c_HashMap == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_HashMap, &_m_HashMap__containsValue, "containsValue", + "(Ljava/lang/Object;)Z"); + if (_m_HashMap__containsValue == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod( + jniEnv, self_, _m_HashMap__containsValue, object); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_HashMap__keySet = NULL; +FFI_PLUGIN_EXPORT +JniResult HashMap__keySet(jobject self_) { + load_env(); + load_class_global_ref(&_c_HashMap, "java/util/HashMap"); + if (_c_HashMap == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_HashMap, &_m_HashMap__keySet, "keySet", "()Ljava/util/Set;"); + if (_m_HashMap__keySet == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_HashMap__keySet); + return to_global_ref_result(_result); +} + +jmethodID _m_HashMap__values = NULL; +FFI_PLUGIN_EXPORT +JniResult HashMap__values(jobject self_) { + load_env(); + load_class_global_ref(&_c_HashMap, "java/util/HashMap"); + if (_c_HashMap == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_HashMap, &_m_HashMap__values, "values", + "()Ljava/util/Collection;"); + if (_m_HashMap__values == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_HashMap__values); + return to_global_ref_result(_result); +} + +jmethodID _m_HashMap__entrySet = NULL; +FFI_PLUGIN_EXPORT +JniResult HashMap__entrySet(jobject self_) { + load_env(); + load_class_global_ref(&_c_HashMap, "java/util/HashMap"); + if (_c_HashMap == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_HashMap, &_m_HashMap__entrySet, "entrySet", + "()Ljava/util/Set;"); + if (_m_HashMap__entrySet == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_HashMap__entrySet); + return to_global_ref_result(_result); +} + +jmethodID _m_HashMap__getOrDefault = NULL; +FFI_PLUGIN_EXPORT +JniResult HashMap__getOrDefault(jobject self_, + jobject object, + jobject object1) { + load_env(); + load_class_global_ref(&_c_HashMap, "java/util/HashMap"); + if (_c_HashMap == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_HashMap, &_m_HashMap__getOrDefault, "getOrDefault", + "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); + if (_m_HashMap__getOrDefault == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_HashMap__getOrDefault, object, object1); + return to_global_ref_result(_result); +} + +jmethodID _m_HashMap__putIfAbsent = NULL; +FFI_PLUGIN_EXPORT +JniResult HashMap__putIfAbsent(jobject self_, jobject object, jobject object1) { + load_env(); + load_class_global_ref(&_c_HashMap, "java/util/HashMap"); + if (_c_HashMap == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_HashMap, &_m_HashMap__putIfAbsent, "putIfAbsent", + "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); + if (_m_HashMap__putIfAbsent == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_HashMap__putIfAbsent, object, object1); + return to_global_ref_result(_result); +} + +jmethodID _m_HashMap__remove1 = NULL; +FFI_PLUGIN_EXPORT +JniResult HashMap__remove1(jobject self_, jobject object, jobject object1) { + load_env(); + load_class_global_ref(&_c_HashMap, "java/util/HashMap"); + if (_c_HashMap == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_HashMap, &_m_HashMap__remove1, "remove", + "(Ljava/lang/Object;Ljava/lang/Object;)Z"); + if (_m_HashMap__remove1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod( + jniEnv, self_, _m_HashMap__remove1, object, object1); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_HashMap__replace = NULL; +FFI_PLUGIN_EXPORT +JniResult HashMap__replace(jobject self_, + jobject object, + jobject object1, + jobject object2) { + load_env(); + load_class_global_ref(&_c_HashMap, "java/util/HashMap"); + if (_c_HashMap == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_HashMap, &_m_HashMap__replace, "replace", + "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Z"); + if (_m_HashMap__replace == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod( + jniEnv, self_, _m_HashMap__replace, object, object1, object2); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_HashMap__replace1 = NULL; +FFI_PLUGIN_EXPORT +JniResult HashMap__replace1(jobject self_, jobject object, jobject object1) { + load_env(); + load_class_global_ref(&_c_HashMap, "java/util/HashMap"); + if (_c_HashMap == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_HashMap, &_m_HashMap__replace1, "replace", + "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); + if (_m_HashMap__replace1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_HashMap__replace1, object, object1); + return to_global_ref_result(_result); +} + +jmethodID _m_HashMap__computeIfAbsent = NULL; +FFI_PLUGIN_EXPORT +JniResult HashMap__computeIfAbsent(jobject self_, + jobject object, + jobject function) { + load_env(); + load_class_global_ref(&_c_HashMap, "java/util/HashMap"); + if (_c_HashMap == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method( + _c_HashMap, &_m_HashMap__computeIfAbsent, "computeIfAbsent", + "(Ljava/lang/Object;Ljava/util/function/Function;)Ljava/lang/Object;"); + if (_m_HashMap__computeIfAbsent == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_HashMap__computeIfAbsent, object, function); + return to_global_ref_result(_result); +} + +jmethodID _m_HashMap__computeIfPresent = NULL; +FFI_PLUGIN_EXPORT +JniResult HashMap__computeIfPresent(jobject self_, + jobject object, + jobject biFunction) { + load_env(); + load_class_global_ref(&_c_HashMap, "java/util/HashMap"); + if (_c_HashMap == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method( + _c_HashMap, &_m_HashMap__computeIfPresent, "computeIfPresent", + "(Ljava/lang/Object;Ljava/util/function/BiFunction;)Ljava/lang/Object;"); + if (_m_HashMap__computeIfPresent == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_HashMap__computeIfPresent, object, biFunction); + return to_global_ref_result(_result); +} + +jmethodID _m_HashMap__compute = NULL; +FFI_PLUGIN_EXPORT +JniResult HashMap__compute(jobject self_, jobject object, jobject biFunction) { + load_env(); + load_class_global_ref(&_c_HashMap, "java/util/HashMap"); + if (_c_HashMap == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method( + _c_HashMap, &_m_HashMap__compute, "compute", + "(Ljava/lang/Object;Ljava/util/function/BiFunction;)Ljava/lang/Object;"); + if (_m_HashMap__compute == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_HashMap__compute, object, biFunction); + return to_global_ref_result(_result); +} + +jmethodID _m_HashMap__merge = NULL; +FFI_PLUGIN_EXPORT +JniResult HashMap__merge(jobject self_, + jobject object, + jobject object1, + jobject biFunction) { + load_env(); + load_class_global_ref(&_c_HashMap, "java/util/HashMap"); + if (_c_HashMap == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_HashMap, &_m_HashMap__merge, "merge", + "(Ljava/lang/Object;Ljava/lang/Object;Ljava/util/function/" + "BiFunction;)Ljava/lang/Object;"); + if (_m_HashMap__merge == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_HashMap__merge, object, object1, biFunction); + return to_global_ref_result(_result); +} + +jmethodID _m_HashMap__forEach = NULL; +FFI_PLUGIN_EXPORT +JniResult HashMap__forEach(jobject self_, jobject biConsumer) { + load_env(); + load_class_global_ref(&_c_HashMap, "java/util/HashMap"); + if (_c_HashMap == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_HashMap, &_m_HashMap__forEach, "forEach", + "(Ljava/util/function/BiConsumer;)V"); + if (_m_HashMap__forEach == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_HashMap__forEach, biConsumer); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_HashMap__replaceAll = NULL; +FFI_PLUGIN_EXPORT +JniResult HashMap__replaceAll(jobject self_, jobject biFunction) { + load_env(); + load_class_global_ref(&_c_HashMap, "java/util/HashMap"); + if (_c_HashMap == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_HashMap, &_m_HashMap__replaceAll, "replaceAll", + "(Ljava/util/function/BiFunction;)V"); + if (_m_HashMap__replaceAll == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_HashMap__replaceAll, biFunction); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_HashMap__clone = NULL; +FFI_PLUGIN_EXPORT +JniResult HashMap__clone(jobject self_) { + load_env(); + load_class_global_ref(&_c_HashMap, "java/util/HashMap"); + if (_c_HashMap == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_HashMap, &_m_HashMap__clone, "clone", "()Ljava/lang/Object;"); + if (_m_HashMap__clone == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_HashMap__clone); + return to_global_ref_result(_result); +} diff --git a/pkgs/jnigen/example/in_app_java/src/android_utils/dartjni.h b/pkgs/jnigen/example/in_app_java/src/android_utils/dartjni.h new file mode 100644 index 000000000..8f1dc7481 --- /dev/null +++ b/pkgs/jnigen/example/in_app_java/src/android_utils/dartjni.h @@ -0,0 +1,424 @@ +// 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. + +#pragma once + +// Note: include appropriate system jni.h as found by CMake, not third_party/jni.h. +#include +#include +#include +#include + +#if _WIN32 +#include +#else +#include +#include +#endif + +#if _WIN32 +#define FFI_PLUGIN_EXPORT __declspec(dllexport) +#else +#define FFI_PLUGIN_EXPORT +#endif + +#if defined _WIN32 +#define thread_local __declspec(thread) +#else +#define thread_local __thread +#endif + +#ifdef __ANDROID__ +#include +#endif + +#ifdef __ANDROID__ +#define __ENVP_CAST (JNIEnv**) +#else +#define __ENVP_CAST (void**) +#endif + +/// Locking functions for windows and pthread. + +#if defined _WIN32 +#include + +typedef CRITICAL_SECTION MutexLock; +typedef CONDITION_VARIABLE ConditionVariable; + +static inline void init_lock(MutexLock* lock) { + InitializeCriticalSection(lock); +} + +static inline void acquire_lock(MutexLock* lock) { + EnterCriticalSection(lock); +} + +static inline void release_lock(MutexLock* lock) { + LeaveCriticalSection(lock); +} + +static inline void destroy_lock(MutexLock* lock) { + DeleteCriticalSection(lock); +} + +static inline void init_cond(ConditionVariable* cond) { + InitializeConditionVariable(cond); +} + +static inline void signal_cond(ConditionVariable* cond) { + WakeConditionVariable(cond); +} + +static inline void wait_for(ConditionVariable* cond, MutexLock* lock) { + SleepConditionVariableCS(cond, lock, INFINITE); +} + +static inline void destroy_cond(ConditionVariable* cond) { + // Not available. +} + +#elif defined __APPLE__ || defined __LINUX__ || defined __ANDROID__ || \ + defined __GNUC__ +#include + +typedef pthread_mutex_t MutexLock; +typedef pthread_cond_t ConditionVariable; + +static inline void init_lock(MutexLock* lock) { + pthread_mutex_init(lock, NULL); +} + +static inline void acquire_lock(MutexLock* lock) { + pthread_mutex_lock(lock); +} + +static inline void release_lock(MutexLock* lock) { + pthread_mutex_unlock(lock); +} + +static inline void destroy_lock(MutexLock* lock) { + pthread_mutex_destroy(lock); +} + +static inline void init_cond(ConditionVariable* cond) { + pthread_cond_init(cond, NULL); +} + +static inline void signal_cond(ConditionVariable* cond) { + pthread_cond_signal(cond); +} + +static inline void wait_for(ConditionVariable* cond, MutexLock* lock) { + pthread_cond_wait(cond, lock); +} + +static inline void destroy_cond(ConditionVariable* cond) { + pthread_cond_destroy(cond); +} + +#else + +#error "No locking/condition variable support; Possibly unsupported platform" + +#endif + +typedef struct CallbackResult { + MutexLock lock; + ConditionVariable cond; + int ready; + jobject object; +} CallbackResult; + +typedef struct JniLocks { + MutexLock classLoadingLock; + MutexLock methodLoadingLock; + MutexLock fieldLoadingLock; +} JniLocks; + +/// Represents the error when dart-jni layer has already spawned singleton VM. +#define DART_JNI_SINGLETON_EXISTS (-99); + +/// Stores the global state of the JNI. +typedef struct JniContext { + JavaVM* jvm; + jobject classLoader; + jmethodID loadClassMethod; + jobject currentActivity; + jobject appContext; + JniLocks locks; +} JniContext; + +// jniEnv for this thread, used by inline functions in this header, +// therefore declared as extern. +extern thread_local JNIEnv* jniEnv; + +extern JniContext* jni; + +/// Types used by JNI API to distinguish between primitive types. +enum JniType { + booleanType = 0, + byteType = 1, + shortType = 2, + charType = 3, + intType = 4, + longType = 5, + floatType = 6, + doubleType = 7, + objectType = 8, + voidType = 9, +}; + +/// Result type for use by JNI. +/// +/// If [exception] is null, it means the result is valid. +/// It's assumed that the caller knows the expected type in [result]. +typedef struct JniResult { + jvalue value; + jthrowable exception; +} JniResult; + +/// Similar to [JniResult] but for class lookups. +typedef struct JniClassLookupResult { + jclass value; + jthrowable exception; +} JniClassLookupResult; + +/// Similar to [JniResult] but for method/field ID lookups. +typedef struct JniPointerResult { + const void* value; + jthrowable exception; +} JniPointerResult; + +/// JniExceptionDetails holds 2 jstring objects, one is the result of +/// calling `toString` on exception object, other is stack trace; +typedef struct JniExceptionDetails { + jstring message; + jstring stacktrace; +} JniExceptionDetails; + +/// This struct contains functions which wrap method call / field access conveniently along with +/// exception checking. +/// +/// Flutter embedding checks for pending JNI exceptions before an FFI transition, which requires us +/// to check for and clear the exception before returning to dart code, which requires these functions +/// to return result types. +typedef struct JniAccessorsStruct { + JniClassLookupResult (*getClass)(char* internalName); + JniPointerResult (*getFieldID)(jclass cls, char* fieldName, char* signature); + JniPointerResult (*getStaticFieldID)(jclass cls, + char* fieldName, + char* signature); + JniPointerResult (*getMethodID)(jclass cls, + char* methodName, + char* signature); + JniPointerResult (*getStaticMethodID)(jclass cls, + char* methodName, + char* signature); + JniResult (*newObject)(jclass cls, jmethodID ctor, jvalue* args); + JniResult (*newPrimitiveArray)(jsize length, int type); + JniResult (*newObjectArray)(jsize length, + jclass elementClass, + jobject initialElement); + JniResult (*getArrayElement)(jarray array, int index, int type); + JniResult (*callMethod)(jobject obj, + jmethodID methodID, + int callType, + jvalue* args); + JniResult (*callStaticMethod)(jclass cls, + jmethodID methodID, + int callType, + jvalue* args); + JniResult (*getField)(jobject obj, jfieldID fieldID, int callType); + JniResult (*getStaticField)(jclass cls, jfieldID fieldID, int callType); + JniExceptionDetails (*getExceptionDetails)(jthrowable exception); +} JniAccessorsStruct; + +FFI_PLUGIN_EXPORT JniAccessorsStruct* GetAccessors(); + +FFI_PLUGIN_EXPORT JavaVM* GetJavaVM(void); + +FFI_PLUGIN_EXPORT JNIEnv* GetJniEnv(void); + +/// Spawn a JVM with given arguments. +/// +/// Returns JNI_OK on success, and one of the documented JNI error codes on +/// failure. It returns DART_JNI_SINGLETON_EXISTS if an attempt to spawn multiple +/// JVMs is made, even if the underlying API potentially supports multiple VMs. +FFI_PLUGIN_EXPORT int SpawnJvm(JavaVMInitArgs* args); + +/// Load class through platform-specific mechanism. +/// +/// Currently uses application classloader on android, +/// and JNIEnv->FindClass on other platforms. +FFI_PLUGIN_EXPORT jclass FindClass(const char* name); + +/// Returns Application classLoader (on Android), +/// which can be used to load application and platform classes. +/// +/// On other platforms, NULL is returned. +FFI_PLUGIN_EXPORT jobject GetClassLoader(void); + +/// Returns application context on Android. +/// +/// On other platforms, NULL is returned. +FFI_PLUGIN_EXPORT jobject GetApplicationContext(void); + +/// Returns current activity of the app on Android. +FFI_PLUGIN_EXPORT jobject GetCurrentActivity(void); + +static inline void attach_thread() { + if (jniEnv == NULL) { + (*jni->jvm)->AttachCurrentThread(jni->jvm, __ENVP_CAST & jniEnv, NULL); + } +} + +/// Load class into [cls] using platform specific mechanism +static inline void load_class_platform(jclass* cls, const char* name) { +#ifdef __ANDROID__ + jstring className = (*jniEnv)->NewStringUTF(jniEnv, name); + *cls = (*jniEnv)->CallObjectMethod(jniEnv, jni->classLoader, + jni->loadClassMethod, className); + (*jniEnv)->DeleteLocalRef(jniEnv, className); +#else + *cls = (*jniEnv)->FindClass(jniEnv, name); +#endif +} + +static inline void load_class_local_ref(jclass* cls, const char* name) { + if (*cls == NULL) { + acquire_lock(&jni->locks.classLoadingLock); + if (*cls == NULL) { + load_class_platform(cls, name); + } + release_lock(&jni->locks.classLoadingLock); + } +} + +static inline void load_class_global_ref(jclass* cls, const char* name) { + if (*cls == NULL) { + jclass tmp = NULL; + acquire_lock(&jni->locks.classLoadingLock); + if (*cls == NULL) { + load_class_platform(&tmp, name); + if (!(*jniEnv)->ExceptionCheck(jniEnv)) { + *cls = (*jniEnv)->NewGlobalRef(jniEnv, tmp); + (*jniEnv)->DeleteLocalRef(jniEnv, tmp); + } + } + release_lock(&jni->locks.classLoadingLock); + } +} + +static inline void load_method(jclass cls, + jmethodID* res, + const char* name, + const char* sig) { + if (*res == NULL) { + acquire_lock(&jni->locks.methodLoadingLock); + if (*res == NULL) { + *res = (*jniEnv)->GetMethodID(jniEnv, cls, name, sig); + } + release_lock(&jni->locks.methodLoadingLock); + } +} + +static inline void load_static_method(jclass cls, + jmethodID* res, + const char* name, + const char* sig) { + if (*res == NULL) { + acquire_lock(&jni->locks.methodLoadingLock); + if (*res == NULL) { + *res = (*jniEnv)->GetStaticMethodID(jniEnv, cls, name, sig); + } + release_lock(&jni->locks.methodLoadingLock); + } +} + +static inline void load_field(jclass cls, + jfieldID* res, + const char* name, + const char* sig) { + if (*res == NULL) { + acquire_lock(&jni->locks.fieldLoadingLock); + if (*res == NULL) { + *res = (*jniEnv)->GetFieldID(jniEnv, cls, name, sig); + } + release_lock(&jni->locks.fieldLoadingLock); + } +} + +static inline void load_static_field(jclass cls, + jfieldID* res, + const char* name, + const char* sig) { + if (*res == NULL) { + acquire_lock(&jni->locks.fieldLoadingLock); + if (*res == NULL) { + *res = (*jniEnv)->GetStaticFieldID(jniEnv, cls, name, sig); + } + release_lock(&jni->locks.fieldLoadingLock); + } +} + +static inline jobject to_global_ref(jobject ref) { + jobject g = (*jniEnv)->NewGlobalRef(jniEnv, ref); + (*jniEnv)->DeleteLocalRef(jniEnv, ref); + return g; +} + +// These functions are useful for C+Dart bindings, and not required for pure dart bindings. + +FFI_PLUGIN_EXPORT JniContext* GetJniContextPtr(); + +/// For use by jni_gen's generated code +/// don't use these. + +// these 2 fn ptr vars will be defined by generated code library +extern JniContext* (*context_getter)(void); +extern JNIEnv* (*env_getter)(void); + +// this function will be exported by generated code library +// it will set above 2 variables. +FFI_PLUGIN_EXPORT void setJniGetters(struct JniContext* (*cg)(void), + JNIEnv* (*eg)(void)); + +static inline void load_env() { + if (jniEnv == NULL) { + jni = context_getter(); + jniEnv = env_getter(); + } +} + +static inline jthrowable check_exception() { + jthrowable exception = (*jniEnv)->ExceptionOccurred(jniEnv); + if (exception != NULL) (*jniEnv)->ExceptionClear(jniEnv); + if (exception == NULL) return NULL; + return to_global_ref(exception); +} + +static inline JniResult to_global_ref_result(jobject ref) { + JniResult result; + result.exception = check_exception(); + if (result.exception == NULL) { + result.value.l = to_global_ref(ref); + } + return result; +} + +FFI_PLUGIN_EXPORT intptr_t InitDartApiDL(void* data); + +FFI_PLUGIN_EXPORT +JniResult DartException__ctor(jstring message); + +FFI_PLUGIN_EXPORT +JniResult PortContinuation__ctor(int64_t j); + +FFI_PLUGIN_EXPORT +JniResult PortProxy__newInstance(jobject binaryName, + int64_t port, + int64_t functionPtr); + +FFI_PLUGIN_EXPORT void resultFor(CallbackResult* result, jobject object); diff --git a/pkgs/jnigen/example/kotlin_plugin/.gitignore b/pkgs/jnigen/example/kotlin_plugin/.gitignore new file mode 100644 index 000000000..96486fd93 --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/.gitignore @@ -0,0 +1,30 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +.packages +build/ diff --git a/pkgs/jnigen/example/kotlin_plugin/.metadata b/pkgs/jnigen/example/kotlin_plugin/.metadata new file mode 100644 index 000000000..227641921 --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 9b4416aaa79bf984d06aa40ab515a274a50a75a7 + channel: beta + +project_type: package diff --git a/pkgs/jnigen/example/kotlin_plugin/README.md b/pkgs/jnigen/example/kotlin_plugin/README.md new file mode 100644 index 000000000..2a915c81c --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/README.md @@ -0,0 +1,38 @@ +# kotlin_plugin + +This example generates bindings for a Kotlin-based library. It showcases the conversion of `suspend fun` in Kotlin to `async` functions in Dart. + +The command to regenerate JNI bindings is: +``` +flutter pub run jnigen --config jnigen.yaml # run from kotlin_plugin project root +``` + +The `example/` app must be built at least once in _release_ mode (eg `flutter build apk`) before running jnigen. This is the equivalent of Gradle Sync in Android Studio, and enables `jnigen` to run a Gradle stub and determine release build's classpath, which contains the paths to relevant dependencies. Therefore a build must have been run after cleaning build directories, or updating Java dependencies. This is a known complexity of the Gradle build system, and if you know a solution, please contribute to issue discussion at #33. + +Note that `jnigen.yaml` of this example contains the option `suspend_fun_to_async: true`. This will generate `async` method bindings from Kotlin's `suspend fun`s. + +For Kotlin coroutines to work, `Jni.initDLApi()` must be run first. + +## Creating a new Kotlin plugin + +Running `flutter create --template=plugin_ffi --platform=android kotlin_plugin` creates the skeleton of an Android plugin. + +In order to use Kotlin, `build.gradle` must be modified in the following way: + +```gradle +apply plugin: 'com.android.library' +// Add the line below: +apply plugin: 'kotlin-android' +``` + +```gradle +android { + // Add the following block + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + // ... +} +``` + +Now the Kotlin code in `src/main/kotlin` is included in the plugin. diff --git a/pkgs/jnigen/example/kotlin_plugin/analysis_options.yaml b/pkgs/jnigen/example/kotlin_plugin/analysis_options.yaml new file mode 100644 index 000000000..f9b303465 --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/analysis_options.yaml @@ -0,0 +1 @@ +include: package:flutter_lints/flutter.yaml diff --git a/pkgs/jnigen/example/kotlin_plugin/android/.gitignore b/pkgs/jnigen/example/kotlin_plugin/android/.gitignore new file mode 100644 index 000000000..161bdcdaf --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/android/.gitignore @@ -0,0 +1,9 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures +.cxx diff --git a/pkgs/jnigen/example/kotlin_plugin/android/build.gradle b/pkgs/jnigen/example/kotlin_plugin/android/build.gradle new file mode 100644 index 000000000..862afafe4 --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/android/build.gradle @@ -0,0 +1,64 @@ +// The Android Gradle Plugin builds the native code with the Android NDK. + +group 'com.example.kotlin_plugin' +version '1.0' + +buildscript { + repositories { + google() + mavenCentral() + } + + dependencies { + // The Android Gradle Plugin knows how to build native code with the NDK. + classpath 'com.android.tools.build:gradle:7.1.2' + } +} + +rootProject.allprojects { + repositories { + google() + mavenCentral() + } +} + +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' + +android { + // Bumping the plugin compileSdkVersion requires all clients of this plugin + // to bump the version in their app. + compileSdkVersion 31 + + // Bumping the plugin ndkVersion requires all clients of this plugin to bump + // the version in their app and to download a newer version of the NDK. + ndkVersion "21.1.6352462" + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + // Invoke the shared CMake build with the Android Gradle Plugin. + externalNativeBuild { + cmake { + path "../src/CMakeLists.txt" + + // The default CMake version for the Android Gradle Plugin is 3.10.2. + // https://developer.android.com/studio/projects/install-ndk#vanilla_cmake + // + // The Flutter tooling requires that developers have CMake 3.10 or later + // installed. You should not increase this version, as doing so will cause + // the plugin to fail to compile for some customers of the plugin. + // version "3.10.2" + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + defaultConfig { + minSdkVersion 16 + } +} diff --git a/pkgs/jnigen/example/kotlin_plugin/android/settings.gradle b/pkgs/jnigen/example/kotlin_plugin/android/settings.gradle new file mode 100644 index 000000000..8e0a5b1a3 --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/android/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'notification_plugin' diff --git a/pkgs/jnigen/example/kotlin_plugin/android/src/main/AndroidManifest.xml b/pkgs/jnigen/example/kotlin_plugin/android/src/main/AndroidManifest.xml new file mode 100644 index 000000000..d7d511a8b --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/android/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ + + diff --git a/pkgs/jnigen/example/kotlin_plugin/android/src/main/kotlin/Example.kt b/pkgs/jnigen/example/kotlin_plugin/android/src/main/kotlin/Example.kt new file mode 100644 index 000000000..531f899b4 --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/android/src/main/kotlin/Example.kt @@ -0,0 +1,10 @@ +import androidx.annotation.Keep +import kotlinx.coroutines.* + +@Keep +class Example { + public suspend fun thinkBeforeAnswering(): String { + delay(1000L) + return "42" + } +} diff --git a/pkgs/jnigen/example/kotlin_plugin/example/.gitignore b/pkgs/jnigen/example/kotlin_plugin/example/.gitignore new file mode 100644 index 000000000..24476c5d1 --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/example/.gitignore @@ -0,0 +1,44 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/pkgs/jnigen/example/kotlin_plugin/example/.metadata b/pkgs/jnigen/example/kotlin_plugin/example/.metadata new file mode 100644 index 000000000..b510dd9e2 --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/example/.metadata @@ -0,0 +1,30 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled. + +version: + revision: 9b4416aaa79bf984d06aa40ab515a274a50a75a7 + channel: beta + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 9b4416aaa79bf984d06aa40ab515a274a50a75a7 + base_revision: 9b4416aaa79bf984d06aa40ab515a274a50a75a7 + - platform: android + create_revision: 9b4416aaa79bf984d06aa40ab515a274a50a75a7 + base_revision: 9b4416aaa79bf984d06aa40ab515a274a50a75a7 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/pkgs/jnigen/example/kotlin_plugin/example/README.md b/pkgs/jnigen/example/kotlin_plugin/example/README.md new file mode 100644 index 000000000..2b3fce4c8 --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/example/README.md @@ -0,0 +1,16 @@ +# example + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) + +For help getting started with Flutter development, view the +[online documentation](https://docs.flutter.dev/), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/pkgs/jnigen/example/kotlin_plugin/example/analysis_options.yaml b/pkgs/jnigen/example/kotlin_plugin/example/analysis_options.yaml new file mode 100644 index 000000000..61b6c4de1 --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/example/analysis_options.yaml @@ -0,0 +1,29 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/pkgs/jnigen/example/kotlin_plugin/example/android/.gitignore b/pkgs/jnigen/example/kotlin_plugin/example/android/.gitignore new file mode 100644 index 000000000..6f568019d --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/example/android/.gitignore @@ -0,0 +1,13 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties +**/*.keystore +**/*.jks diff --git a/pkgs/jnigen/example/kotlin_plugin/example/android/app/build.gradle b/pkgs/jnigen/example/kotlin_plugin/example/android/app/build.gradle new file mode 100644 index 000000000..7f1cb3e67 --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/example/android/app/build.gradle @@ -0,0 +1,71 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new FileNotFoundException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion flutter.compileSdkVersion + ndkVersion flutter.ndkVersion + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.kotlin_plugin.example" + // You can update the following values to match your application needs. + // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. + minSdkVersion flutter.minSdkVersion + targetSdkVersion flutter.targetSdkVersion + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/pkgs/jnigen/example/kotlin_plugin/example/android/app/proguard-rules.pro b/pkgs/jnigen/example/kotlin_plugin/example/android/app/proguard-rules.pro new file mode 100644 index 000000000..8c1218b7c --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/example/android/app/proguard-rules.pro @@ -0,0 +1 @@ +-keep class kotlin.coroutines.** { *; } diff --git a/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/debug/AndroidManifest.xml b/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 000000000..0d1fc86d2 --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,8 @@ + + + + diff --git a/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/main/AndroidManifest.xml b/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..9059f10e2 --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + diff --git a/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/main/kotlin/com/example/kotlin_plugin/example/MainActivity.kt b/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/main/kotlin/com/example/kotlin_plugin/example/MainActivity.kt new file mode 100644 index 000000000..4826f822e --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/main/kotlin/com/example/kotlin_plugin/example/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.kotlin_plugin.example + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} diff --git a/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/main/res/drawable-v21/launch_background.xml b/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 000000000..f74085f3f --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/main/res/drawable/launch_background.xml b/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 000000000..304732f88 --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..db77bb4b7 Binary files /dev/null and b/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..17987b79b Binary files /dev/null and b/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..09d439148 Binary files /dev/null and b/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..d5f1c8d34 Binary files /dev/null and b/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..4d6372eeb Binary files /dev/null and b/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/main/res/values-night/styles.xml b/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 000000000..06952be74 --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/main/res/values/styles.xml b/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/main/res/values/styles.xml new file mode 100644 index 000000000..cb1ef8805 --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/profile/AndroidManifest.xml b/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 000000000..2c06d9bc1 --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/example/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,8 @@ + + + + diff --git a/pkgs/jnigen/example/kotlin_plugin/example/android/build.gradle b/pkgs/jnigen/example/kotlin_plugin/example/android/build.gradle new file mode 100644 index 000000000..713d7f6e6 --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/example/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.7.10' + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:7.2.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +tasks.register("clean", Delete) { + delete rootProject.buildDir +} diff --git a/pkgs/jnigen/example/kotlin_plugin/example/android/gradle.properties b/pkgs/jnigen/example/kotlin_plugin/example/android/gradle.properties new file mode 100644 index 000000000..94adc3a3f --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/example/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true diff --git a/pkgs/jnigen/example/kotlin_plugin/example/android/gradle/wrapper/gradle-wrapper.properties b/pkgs/jnigen/example/kotlin_plugin/example/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..3c472b99c --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/example/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip diff --git a/pkgs/jnigen/example/kotlin_plugin/example/android/settings.gradle b/pkgs/jnigen/example/kotlin_plugin/example/android/settings.gradle new file mode 100644 index 000000000..44e62bcf0 --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/example/android/settings.gradle @@ -0,0 +1,11 @@ +include ':app' + +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() + +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/pkgs/jnigen/example/kotlin_plugin/example/lib/main.dart b/pkgs/jnigen/example/kotlin_plugin/example/lib/main.dart new file mode 100644 index 000000000..50d14348b --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/example/lib/main.dart @@ -0,0 +1,98 @@ +import 'package:flutter/material.dart'; +import 'package:kotlin_plugin/kotlin_plugin.dart'; +import 'package:jni/jni.dart'; + +void main() { + Jni.initDLApi(); + runApp(const MyApp()); +} + +class MyApp extends StatelessWidget { + const MyApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Kotlin Plugin Example', + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home: const MyHomePage(title: 'Kotlin Plugin Example Home Page'), + ); + } +} + +class MyHomePage extends StatefulWidget { + const MyHomePage({super.key, required this.title}); + + final String title; + + @override + State createState() => _MyHomePageState(); +} + +class _MyHomePageState extends State { + Future? answer; + + late Example example; + + @override + void initState() { + super.initState(); + example = Example(); + } + + @override + void dispose() { + example.release(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(widget.title), + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text( + 'What is the answer to life, the universe, and everything?', + ), + ElevatedButton( + onPressed: () { + setState(() { + answer = example.thinkBeforeAnswering().then( + (value) => value.toDartString(releaseOriginal: true)); + }); + }, + child: const Text('Think...'), + ), + FutureBuilder( + future: answer, + builder: (context, snapshot) { + switch (snapshot.connectionState) { + case ConnectionState.none: + return const SizedBox(); + case ConnectionState.waiting: + case ConnectionState.active: + return Text( + 'Thinking...', + style: Theme.of(context).textTheme.headlineMedium, + ); + case ConnectionState.done: + return Text( + snapshot.data ?? "I don't know!", + style: Theme.of(context).textTheme.headlineMedium, + ); + } + }, + ), + ], + ), + ), + ); + } +} diff --git a/pkgs/jnigen/example/kotlin_plugin/example/pubspec.yaml b/pkgs/jnigen/example/kotlin_plugin/example/pubspec.yaml new file mode 100644 index 000000000..4c1c79651 --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/example/pubspec.yaml @@ -0,0 +1,29 @@ +name: example +description: A new Flutter project. + +publish_to: "none" + +version: 1.0.0+1 + +environment: + sdk: '>=3.1.0 <4.0.0' + +dependencies: + flutter: + sdk: flutter + + kotlin_plugin: + path: ../ + + jni: + path: ../../../../jni + +dev_dependencies: + flutter_test: + sdk: flutter + + flutter_lints: ^2.0.0 + +flutter: + uses-material-design: true + diff --git a/pkgs/jnigen/example/kotlin_plugin/jnigen.yaml b/pkgs/jnigen/example/kotlin_plugin/jnigen.yaml new file mode 100644 index 000000000..60978f56f --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/jnigen.yaml @@ -0,0 +1,21 @@ +android_sdk_config: + add_gradle_deps: true + android_example: 'example/' + +summarizer: + backend: asm + +suspend_fun_to_async: true + +output: + c: + library_name: kotlin_plugin_bindings + path: src/ + dart: + path: lib/kotlin_bindings.dart + structure: single_file + +log_level: all + +classes: + - 'Example' diff --git a/pkgs/jnigen/example/kotlin_plugin/lib/kotlin_bindings.dart b/pkgs/jnigen/example/kotlin_plugin/lib/kotlin_bindings.dart new file mode 100644 index 000000000..efd0351f8 --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/lib/kotlin_bindings.dart @@ -0,0 +1,96 @@ +// Autogenerated by jnigen. DO NOT EDIT! + +// ignore_for_file: annotate_overrides +// ignore_for_file: camel_case_extensions +// ignore_for_file: camel_case_types +// ignore_for_file: constant_identifier_names +// ignore_for_file: file_names +// ignore_for_file: lines_longer_than_80_chars +// ignore_for_file: no_leading_underscores_for_local_identifiers +// ignore_for_file: non_constant_identifier_names +// ignore_for_file: overridden_fields +// ignore_for_file: unnecessary_cast +// ignore_for_file: unused_element +// ignore_for_file: unused_field +// ignore_for_file: unused_import +// ignore_for_file: unused_local_variable +// ignore_for_file: unused_shown_name + +import "dart:isolate" show ReceivePort; +import "dart:ffi" as ffi; +import "package:jni/internal_helpers_for_jnigen.dart"; +import "package:jni/jni.dart" as jni; + +// Auto-generated initialization code. + +final ffi.Pointer Function(String sym) jniLookup = + ProtectedJniExtensions.initGeneratedLibrary("kotlin_plugin_bindings"); + +/// from: Example +class Example extends jni.JObject { + @override + late final jni.JObjType $type = type; + + Example.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $ExampleType(); + static final _new0 = + jniLookup>("Example__new0") + .asFunction(); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory Example() { + return Example.fromRef(_new0().object); + } + + static final _thinkBeforeAnswering = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("Example__thinkBeforeAnswering") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public final java.lang.Object thinkBeforeAnswering(kotlin.coroutines.Continuation continuation) + /// The returned object must be released after use, by calling the [release] method. + Future thinkBeforeAnswering() async { + final $p = ReceivePort(); + final $c = + jni.JObject.fromRef(ProtectedJniExtensions.newPortContinuation($p)); + _thinkBeforeAnswering(reference, $c.reference).object; + final $o = jni.JObjectPtr.fromAddress(await $p.first); + final $k = const jni.JStringType().getClass().reference; + if (!jni.Jni.env.IsInstanceOf($o, $k)) { + throw "Failed"; + } + return const jni.JStringType().fromRef($o); + } +} + +final class $ExampleType extends jni.JObjType { + const $ExampleType(); + + @override + String get signature => r"LExample;"; + + @override + Example fromRef(jni.JObjectPtr ref) => Example.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($ExampleType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($ExampleType) && other is $ExampleType; + } +} diff --git a/pkgs/jnigen/example/kotlin_plugin/lib/kotlin_plugin.dart b/pkgs/jnigen/example/kotlin_plugin/lib/kotlin_plugin.dart new file mode 100644 index 000000000..5919c221b --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/lib/kotlin_plugin.dart @@ -0,0 +1,3 @@ +library kotlin_plugin; + +export 'kotlin_bindings.dart'; diff --git a/pkgs/jnigen/example/kotlin_plugin/pubspec.yaml b/pkgs/jnigen/example/kotlin_plugin/pubspec.yaml new file mode 100644 index 000000000..fd89ad6cc --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/pubspec.yaml @@ -0,0 +1,31 @@ +# Copyright (c) 2023, 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. + +name: kotlin_plugin +description: Example of using jnigen to generate bindings for Kotlin. +version: 0.0.1 +publish_to: none + +environment: + sdk: '>=3.1.0 <4.0.0' + flutter: ">=1.17.0" + +dependencies: + flutter: + sdk: flutter + jni: + path: ../../../jni + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^2.0.0 + jnigen: + path: ../../ + +flutter: + plugin: + platforms: + android: + ffiPlugin: true diff --git a/pkgs/jnigen/example/kotlin_plugin/src/.clang-format b/pkgs/jnigen/example/kotlin_plugin/src/.clang-format new file mode 100644 index 000000000..a256c2f09 --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/src/.clang-format @@ -0,0 +1,15 @@ +# From dart SDK: https://github.com/dart-lang/sdk/blob/main/.clang-format + +# Defines the Chromium style for automatic reformatting. +# http://clang.llvm.org/docs/ClangFormatStyleOptions.html +BasedOnStyle: Chromium + +# clang-format doesn't seem to do a good job of this for longer comments. +ReflowComments: 'false' + +# We have lots of these. Though we need to put them all in curly braces, +# clang-format can't do that. +AllowShortIfStatementsOnASingleLine: 'true' + +# Put escaped newlines into the rightmost column. +AlignEscapedNewlinesLeft: false diff --git a/pkgs/jnigen/example/kotlin_plugin/src/CMakeLists.txt b/pkgs/jnigen/example/kotlin_plugin/src/CMakeLists.txt new file mode 100644 index 000000000..78d9dca2c --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/src/CMakeLists.txt @@ -0,0 +1,32 @@ +# jni_native_build (Build with jni:setup. Do not delete this line.) + +# The Flutter tooling requires that developers have CMake 3.10 or later +# installed. You should not increase this version, as doing so will cause +# the plugin to fail to compile for some customers of the plugin. +cmake_minimum_required(VERSION 3.10) + +project(kotlin_plugin_bindings VERSION 0.0.1 LANGUAGES C) + +add_library(kotlin_plugin_bindings SHARED + "./kotlin_plugin_bindings.c" +) + +set_target_properties(kotlin_plugin_bindings PROPERTIES + OUTPUT_NAME "kotlin_plugin_bindings" +) + +target_compile_definitions(kotlin_plugin_bindings PUBLIC DART_SHARED_LIB) + +if(WIN32) + set_target_properties(${TARGET_NAME} PROPERTIES + LINK_FLAGS "/DELAYLOAD:jvm.dll") +endif() + +if (ANDROID) + target_link_libraries(kotlin_plugin_bindings log) +else() + find_package(Java REQUIRED) + find_package(JNI REQUIRED) + include_directories(${JNI_INCLUDE_DIRS}) + target_link_libraries(kotlin_plugin_bindings ${JNI_LIBRARIES}) +endif() diff --git a/pkgs/jnigen/example/kotlin_plugin/src/dartjni.h b/pkgs/jnigen/example/kotlin_plugin/src/dartjni.h new file mode 100644 index 000000000..8f1dc7481 --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/src/dartjni.h @@ -0,0 +1,424 @@ +// 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. + +#pragma once + +// Note: include appropriate system jni.h as found by CMake, not third_party/jni.h. +#include +#include +#include +#include + +#if _WIN32 +#include +#else +#include +#include +#endif + +#if _WIN32 +#define FFI_PLUGIN_EXPORT __declspec(dllexport) +#else +#define FFI_PLUGIN_EXPORT +#endif + +#if defined _WIN32 +#define thread_local __declspec(thread) +#else +#define thread_local __thread +#endif + +#ifdef __ANDROID__ +#include +#endif + +#ifdef __ANDROID__ +#define __ENVP_CAST (JNIEnv**) +#else +#define __ENVP_CAST (void**) +#endif + +/// Locking functions for windows and pthread. + +#if defined _WIN32 +#include + +typedef CRITICAL_SECTION MutexLock; +typedef CONDITION_VARIABLE ConditionVariable; + +static inline void init_lock(MutexLock* lock) { + InitializeCriticalSection(lock); +} + +static inline void acquire_lock(MutexLock* lock) { + EnterCriticalSection(lock); +} + +static inline void release_lock(MutexLock* lock) { + LeaveCriticalSection(lock); +} + +static inline void destroy_lock(MutexLock* lock) { + DeleteCriticalSection(lock); +} + +static inline void init_cond(ConditionVariable* cond) { + InitializeConditionVariable(cond); +} + +static inline void signal_cond(ConditionVariable* cond) { + WakeConditionVariable(cond); +} + +static inline void wait_for(ConditionVariable* cond, MutexLock* lock) { + SleepConditionVariableCS(cond, lock, INFINITE); +} + +static inline void destroy_cond(ConditionVariable* cond) { + // Not available. +} + +#elif defined __APPLE__ || defined __LINUX__ || defined __ANDROID__ || \ + defined __GNUC__ +#include + +typedef pthread_mutex_t MutexLock; +typedef pthread_cond_t ConditionVariable; + +static inline void init_lock(MutexLock* lock) { + pthread_mutex_init(lock, NULL); +} + +static inline void acquire_lock(MutexLock* lock) { + pthread_mutex_lock(lock); +} + +static inline void release_lock(MutexLock* lock) { + pthread_mutex_unlock(lock); +} + +static inline void destroy_lock(MutexLock* lock) { + pthread_mutex_destroy(lock); +} + +static inline void init_cond(ConditionVariable* cond) { + pthread_cond_init(cond, NULL); +} + +static inline void signal_cond(ConditionVariable* cond) { + pthread_cond_signal(cond); +} + +static inline void wait_for(ConditionVariable* cond, MutexLock* lock) { + pthread_cond_wait(cond, lock); +} + +static inline void destroy_cond(ConditionVariable* cond) { + pthread_cond_destroy(cond); +} + +#else + +#error "No locking/condition variable support; Possibly unsupported platform" + +#endif + +typedef struct CallbackResult { + MutexLock lock; + ConditionVariable cond; + int ready; + jobject object; +} CallbackResult; + +typedef struct JniLocks { + MutexLock classLoadingLock; + MutexLock methodLoadingLock; + MutexLock fieldLoadingLock; +} JniLocks; + +/// Represents the error when dart-jni layer has already spawned singleton VM. +#define DART_JNI_SINGLETON_EXISTS (-99); + +/// Stores the global state of the JNI. +typedef struct JniContext { + JavaVM* jvm; + jobject classLoader; + jmethodID loadClassMethod; + jobject currentActivity; + jobject appContext; + JniLocks locks; +} JniContext; + +// jniEnv for this thread, used by inline functions in this header, +// therefore declared as extern. +extern thread_local JNIEnv* jniEnv; + +extern JniContext* jni; + +/// Types used by JNI API to distinguish between primitive types. +enum JniType { + booleanType = 0, + byteType = 1, + shortType = 2, + charType = 3, + intType = 4, + longType = 5, + floatType = 6, + doubleType = 7, + objectType = 8, + voidType = 9, +}; + +/// Result type for use by JNI. +/// +/// If [exception] is null, it means the result is valid. +/// It's assumed that the caller knows the expected type in [result]. +typedef struct JniResult { + jvalue value; + jthrowable exception; +} JniResult; + +/// Similar to [JniResult] but for class lookups. +typedef struct JniClassLookupResult { + jclass value; + jthrowable exception; +} JniClassLookupResult; + +/// Similar to [JniResult] but for method/field ID lookups. +typedef struct JniPointerResult { + const void* value; + jthrowable exception; +} JniPointerResult; + +/// JniExceptionDetails holds 2 jstring objects, one is the result of +/// calling `toString` on exception object, other is stack trace; +typedef struct JniExceptionDetails { + jstring message; + jstring stacktrace; +} JniExceptionDetails; + +/// This struct contains functions which wrap method call / field access conveniently along with +/// exception checking. +/// +/// Flutter embedding checks for pending JNI exceptions before an FFI transition, which requires us +/// to check for and clear the exception before returning to dart code, which requires these functions +/// to return result types. +typedef struct JniAccessorsStruct { + JniClassLookupResult (*getClass)(char* internalName); + JniPointerResult (*getFieldID)(jclass cls, char* fieldName, char* signature); + JniPointerResult (*getStaticFieldID)(jclass cls, + char* fieldName, + char* signature); + JniPointerResult (*getMethodID)(jclass cls, + char* methodName, + char* signature); + JniPointerResult (*getStaticMethodID)(jclass cls, + char* methodName, + char* signature); + JniResult (*newObject)(jclass cls, jmethodID ctor, jvalue* args); + JniResult (*newPrimitiveArray)(jsize length, int type); + JniResult (*newObjectArray)(jsize length, + jclass elementClass, + jobject initialElement); + JniResult (*getArrayElement)(jarray array, int index, int type); + JniResult (*callMethod)(jobject obj, + jmethodID methodID, + int callType, + jvalue* args); + JniResult (*callStaticMethod)(jclass cls, + jmethodID methodID, + int callType, + jvalue* args); + JniResult (*getField)(jobject obj, jfieldID fieldID, int callType); + JniResult (*getStaticField)(jclass cls, jfieldID fieldID, int callType); + JniExceptionDetails (*getExceptionDetails)(jthrowable exception); +} JniAccessorsStruct; + +FFI_PLUGIN_EXPORT JniAccessorsStruct* GetAccessors(); + +FFI_PLUGIN_EXPORT JavaVM* GetJavaVM(void); + +FFI_PLUGIN_EXPORT JNIEnv* GetJniEnv(void); + +/// Spawn a JVM with given arguments. +/// +/// Returns JNI_OK on success, and one of the documented JNI error codes on +/// failure. It returns DART_JNI_SINGLETON_EXISTS if an attempt to spawn multiple +/// JVMs is made, even if the underlying API potentially supports multiple VMs. +FFI_PLUGIN_EXPORT int SpawnJvm(JavaVMInitArgs* args); + +/// Load class through platform-specific mechanism. +/// +/// Currently uses application classloader on android, +/// and JNIEnv->FindClass on other platforms. +FFI_PLUGIN_EXPORT jclass FindClass(const char* name); + +/// Returns Application classLoader (on Android), +/// which can be used to load application and platform classes. +/// +/// On other platforms, NULL is returned. +FFI_PLUGIN_EXPORT jobject GetClassLoader(void); + +/// Returns application context on Android. +/// +/// On other platforms, NULL is returned. +FFI_PLUGIN_EXPORT jobject GetApplicationContext(void); + +/// Returns current activity of the app on Android. +FFI_PLUGIN_EXPORT jobject GetCurrentActivity(void); + +static inline void attach_thread() { + if (jniEnv == NULL) { + (*jni->jvm)->AttachCurrentThread(jni->jvm, __ENVP_CAST & jniEnv, NULL); + } +} + +/// Load class into [cls] using platform specific mechanism +static inline void load_class_platform(jclass* cls, const char* name) { +#ifdef __ANDROID__ + jstring className = (*jniEnv)->NewStringUTF(jniEnv, name); + *cls = (*jniEnv)->CallObjectMethod(jniEnv, jni->classLoader, + jni->loadClassMethod, className); + (*jniEnv)->DeleteLocalRef(jniEnv, className); +#else + *cls = (*jniEnv)->FindClass(jniEnv, name); +#endif +} + +static inline void load_class_local_ref(jclass* cls, const char* name) { + if (*cls == NULL) { + acquire_lock(&jni->locks.classLoadingLock); + if (*cls == NULL) { + load_class_platform(cls, name); + } + release_lock(&jni->locks.classLoadingLock); + } +} + +static inline void load_class_global_ref(jclass* cls, const char* name) { + if (*cls == NULL) { + jclass tmp = NULL; + acquire_lock(&jni->locks.classLoadingLock); + if (*cls == NULL) { + load_class_platform(&tmp, name); + if (!(*jniEnv)->ExceptionCheck(jniEnv)) { + *cls = (*jniEnv)->NewGlobalRef(jniEnv, tmp); + (*jniEnv)->DeleteLocalRef(jniEnv, tmp); + } + } + release_lock(&jni->locks.classLoadingLock); + } +} + +static inline void load_method(jclass cls, + jmethodID* res, + const char* name, + const char* sig) { + if (*res == NULL) { + acquire_lock(&jni->locks.methodLoadingLock); + if (*res == NULL) { + *res = (*jniEnv)->GetMethodID(jniEnv, cls, name, sig); + } + release_lock(&jni->locks.methodLoadingLock); + } +} + +static inline void load_static_method(jclass cls, + jmethodID* res, + const char* name, + const char* sig) { + if (*res == NULL) { + acquire_lock(&jni->locks.methodLoadingLock); + if (*res == NULL) { + *res = (*jniEnv)->GetStaticMethodID(jniEnv, cls, name, sig); + } + release_lock(&jni->locks.methodLoadingLock); + } +} + +static inline void load_field(jclass cls, + jfieldID* res, + const char* name, + const char* sig) { + if (*res == NULL) { + acquire_lock(&jni->locks.fieldLoadingLock); + if (*res == NULL) { + *res = (*jniEnv)->GetFieldID(jniEnv, cls, name, sig); + } + release_lock(&jni->locks.fieldLoadingLock); + } +} + +static inline void load_static_field(jclass cls, + jfieldID* res, + const char* name, + const char* sig) { + if (*res == NULL) { + acquire_lock(&jni->locks.fieldLoadingLock); + if (*res == NULL) { + *res = (*jniEnv)->GetStaticFieldID(jniEnv, cls, name, sig); + } + release_lock(&jni->locks.fieldLoadingLock); + } +} + +static inline jobject to_global_ref(jobject ref) { + jobject g = (*jniEnv)->NewGlobalRef(jniEnv, ref); + (*jniEnv)->DeleteLocalRef(jniEnv, ref); + return g; +} + +// These functions are useful for C+Dart bindings, and not required for pure dart bindings. + +FFI_PLUGIN_EXPORT JniContext* GetJniContextPtr(); + +/// For use by jni_gen's generated code +/// don't use these. + +// these 2 fn ptr vars will be defined by generated code library +extern JniContext* (*context_getter)(void); +extern JNIEnv* (*env_getter)(void); + +// this function will be exported by generated code library +// it will set above 2 variables. +FFI_PLUGIN_EXPORT void setJniGetters(struct JniContext* (*cg)(void), + JNIEnv* (*eg)(void)); + +static inline void load_env() { + if (jniEnv == NULL) { + jni = context_getter(); + jniEnv = env_getter(); + } +} + +static inline jthrowable check_exception() { + jthrowable exception = (*jniEnv)->ExceptionOccurred(jniEnv); + if (exception != NULL) (*jniEnv)->ExceptionClear(jniEnv); + if (exception == NULL) return NULL; + return to_global_ref(exception); +} + +static inline JniResult to_global_ref_result(jobject ref) { + JniResult result; + result.exception = check_exception(); + if (result.exception == NULL) { + result.value.l = to_global_ref(ref); + } + return result; +} + +FFI_PLUGIN_EXPORT intptr_t InitDartApiDL(void* data); + +FFI_PLUGIN_EXPORT +JniResult DartException__ctor(jstring message); + +FFI_PLUGIN_EXPORT +JniResult PortContinuation__ctor(int64_t j); + +FFI_PLUGIN_EXPORT +JniResult PortProxy__newInstance(jobject binaryName, + int64_t port, + int64_t functionPtr); + +FFI_PLUGIN_EXPORT void resultFor(CallbackResult* result, jobject object); diff --git a/pkgs/jnigen/example/kotlin_plugin/src/kotlin_plugin_bindings.c b/pkgs/jnigen/example/kotlin_plugin/src/kotlin_plugin_bindings.c new file mode 100644 index 000000000..28a2af621 --- /dev/null +++ b/pkgs/jnigen/example/kotlin_plugin/src/kotlin_plugin_bindings.c @@ -0,0 +1,50 @@ +// Autogenerated by jnigen. DO NOT EDIT! + +#include +#include "dartjni.h" +#include "jni.h" + +thread_local JNIEnv* jniEnv; +JniContext* jni; + +JniContext* (*context_getter)(void); +JNIEnv* (*env_getter)(void); + +void setJniGetters(JniContext* (*cg)(void), JNIEnv* (*eg)(void)) { + context_getter = cg; + env_getter = eg; +} + +// Example +jclass _c_Example = NULL; + +jmethodID _m_Example__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__new0() { + load_env(); + load_class_global_ref(&_c_Example, "Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example, &_m_Example__new0, "", "()V"); + if (_m_Example__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject(jniEnv, _c_Example, _m_Example__new0); + return to_global_ref_result(_result); +} + +jmethodID _m_Example__thinkBeforeAnswering = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__thinkBeforeAnswering(jobject self_, jobject continuation) { + load_env(); + load_class_global_ref(&_c_Example, "Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example, &_m_Example__thinkBeforeAnswering, + "thinkBeforeAnswering", + "(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;"); + if (_m_Example__thinkBeforeAnswering == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_Example__thinkBeforeAnswering, continuation); + return to_global_ref_result(_result); +} diff --git a/pkgs/jnigen/example/notification_plugin/.gitignore b/pkgs/jnigen/example/notification_plugin/.gitignore new file mode 100644 index 000000000..96486fd93 --- /dev/null +++ b/pkgs/jnigen/example/notification_plugin/.gitignore @@ -0,0 +1,30 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +.packages +build/ diff --git a/pkgs/jnigen/example/notification_plugin/.metadata b/pkgs/jnigen/example/notification_plugin/.metadata new file mode 100644 index 000000000..d677252b9 --- /dev/null +++ b/pkgs/jnigen/example/notification_plugin/.metadata @@ -0,0 +1,30 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled. + +version: + revision: ffccd96b62ee8cec7740dab303538c5fc26ac543 + channel: stable + +project_type: plugin_ffi + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: ffccd96b62ee8cec7740dab303538c5fc26ac543 + base_revision: ffccd96b62ee8cec7740dab303538c5fc26ac543 + - platform: android + create_revision: ffccd96b62ee8cec7740dab303538c5fc26ac543 + base_revision: ffccd96b62ee8cec7740dab303538c5fc26ac543 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/pkgs/jnigen/example/notification_plugin/README.md b/pkgs/jnigen/example/notification_plugin/README.md new file mode 100644 index 000000000..e1b3af5d5 --- /dev/null +++ b/pkgs/jnigen/example/notification_plugin/README.md @@ -0,0 +1,13 @@ +# notification_plugin + +Example of Android plugin project with jnigen. + +This plugin project contains [custom code](android/src/main/java/com/example/notification_plugin) which uses the Android libraries. The bindings are generated using [jnigen config](jnigen.yaml) and then used in [flutter example](example/lib/main.dart), with help of `package:jni` APIs. + +The command to regenerate JNI bindings is: +``` +flutter pub run jnigen --config jnigen.yaml # run from notification_plugin project root +``` + +The `example/` app must be built at least once in _release_ mode (eg `flutter build apk`) before running jnigen. This is the equivalent of Gradle Sync in Android Studio, and enables `jnigen` to run a Gradle stub and determine release build's classpath, which contains the paths to relevant dependencies. Therefore a build must have been run after cleaning build directories, or updating Java dependencies. This is a known complexity of the Gradle build system, and if you know a solution, please contribute to issue discussion at #33. + diff --git a/pkgs/jnigen/example/notification_plugin/analysis_options.yaml b/pkgs/jnigen/example/notification_plugin/analysis_options.yaml new file mode 100644 index 000000000..a5744c1cf --- /dev/null +++ b/pkgs/jnigen/example/notification_plugin/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:flutter_lints/flutter.yaml + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/pkgs/jnigen/example/notification_plugin/android/.gitignore b/pkgs/jnigen/example/notification_plugin/android/.gitignore new file mode 100644 index 000000000..161bdcdaf --- /dev/null +++ b/pkgs/jnigen/example/notification_plugin/android/.gitignore @@ -0,0 +1,9 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures +.cxx diff --git a/pkgs/jnigen/example/notification_plugin/android/build.gradle b/pkgs/jnigen/example/notification_plugin/android/build.gradle new file mode 100644 index 000000000..7643ec56e --- /dev/null +++ b/pkgs/jnigen/example/notification_plugin/android/build.gradle @@ -0,0 +1,59 @@ +// The Android Gradle Plugin builds the native code with the Android NDK. + +group 'com.example.notification_plugin' +version '1.0' + +buildscript { + repositories { + google() + mavenCentral() + } + + dependencies { + // The Android Gradle Plugin knows how to build native code with the NDK. + classpath 'com.android.tools.build:gradle:7.1.2' + } +} + +rootProject.allprojects { + repositories { + google() + mavenCentral() + } +} + +apply plugin: 'com.android.library' + +android { + // Bumping the plugin compileSdkVersion requires all clients of this plugin + // to bump the version in their app. + compileSdkVersion 31 + + // Bumping the plugin ndkVersion requires all clients of this plugin to bump + // the version in their app and to download a newer version of the NDK. + ndkVersion "21.1.6352462" + + // Invoke the shared CMake build with the Android Gradle Plugin. + externalNativeBuild { + cmake { + path "../src/CMakeLists.txt" + + // The default CMake version for the Android Gradle Plugin is 3.10.2. + // https://developer.android.com/studio/projects/install-ndk#vanilla_cmake + // + // The Flutter tooling requires that developers have CMake 3.10 or later + // installed. You should not increase this version, as doing so will cause + // the plugin to fail to compile for some customers of the plugin. + // version "3.10.2" + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + defaultConfig { + minSdkVersion 16 + } +} diff --git a/pkgs/jnigen/example/notification_plugin/android/settings.gradle b/pkgs/jnigen/example/notification_plugin/android/settings.gradle new file mode 100644 index 000000000..8e0a5b1a3 --- /dev/null +++ b/pkgs/jnigen/example/notification_plugin/android/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'notification_plugin' diff --git a/pkgs/jnigen/example/notification_plugin/android/src/main/AndroidManifest.xml b/pkgs/jnigen/example/notification_plugin/android/src/main/AndroidManifest.xml new file mode 100644 index 000000000..01cb16564 --- /dev/null +++ b/pkgs/jnigen/example/notification_plugin/android/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ + + diff --git a/pkgs/jnigen/example/notification_plugin/android/src/main/java/com/example/notification_plugin/Notifications.java b/pkgs/jnigen/example/notification_plugin/android/src/main/java/com/example/notification_plugin/Notifications.java new file mode 100644 index 000000000..59f8b7a74 --- /dev/null +++ b/pkgs/jnigen/example/notification_plugin/android/src/main/java/com/example/notification_plugin/Notifications.java @@ -0,0 +1,36 @@ +// 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.example.notification_plugin; + +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.content.Context; +import android.os.Build; +import androidx.annotation.Keep; +import androidx.core.app.NotificationCompat; + +@Keep +public class Notifications { + public static void showNotification( + Context context, int notificationID, String title, String text) { + @SuppressWarnings("deprecation") + NotificationCompat.Builder builder = + new NotificationCompat.Builder(context) + .setSmallIcon(android.R.drawable.ic_dialog_info) + .setContentTitle(title) + .setContentText(text); + NotificationManager notificationManager = + (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O) { + String channelId = "my_channel"; + NotificationChannel channel = + new NotificationChannel( + channelId, "My App's notifications", NotificationManager.IMPORTANCE_HIGH); + notificationManager.createNotificationChannel(channel); + builder.setChannelId(channelId); + } + notificationManager.notify(notificationID, builder.build()); + } +} diff --git a/pkgs/jnigen/example/notification_plugin/example/.gitignore b/pkgs/jnigen/example/notification_plugin/example/.gitignore new file mode 100644 index 000000000..24476c5d1 --- /dev/null +++ b/pkgs/jnigen/example/notification_plugin/example/.gitignore @@ -0,0 +1,44 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/pkgs/jnigen/example/notification_plugin/example/README.md b/pkgs/jnigen/example/notification_plugin/example/README.md new file mode 100644 index 000000000..0ec9e1d6c --- /dev/null +++ b/pkgs/jnigen/example/notification_plugin/example/README.md @@ -0,0 +1,4 @@ +# notification_plugin_example + +This app demonstrates how to use the notification_plugin plugin. + diff --git a/pkgs/jnigen/example/notification_plugin/example/analysis_options.yaml b/pkgs/jnigen/example/notification_plugin/example/analysis_options.yaml new file mode 100644 index 000000000..61b6c4de1 --- /dev/null +++ b/pkgs/jnigen/example/notification_plugin/example/analysis_options.yaml @@ -0,0 +1,29 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/pkgs/jnigen/example/notification_plugin/example/android/.gitignore b/pkgs/jnigen/example/notification_plugin/example/android/.gitignore new file mode 100644 index 000000000..6f568019d --- /dev/null +++ b/pkgs/jnigen/example/notification_plugin/example/android/.gitignore @@ -0,0 +1,13 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties +**/*.keystore +**/*.jks diff --git a/pkgs/jnigen/example/notification_plugin/example/android/app/build.gradle b/pkgs/jnigen/example/notification_plugin/example/android/app/build.gradle new file mode 100644 index 000000000..7f66900ca --- /dev/null +++ b/pkgs/jnigen/example/notification_plugin/example/android/app/build.gradle @@ -0,0 +1,71 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new FileNotFoundException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion flutter.compileSdkVersion + ndkVersion flutter.ndkVersion + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.notification_plugin_example" + // You can update the following values to match your application needs. + // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration. + minSdkVersion flutter.minSdkVersion + targetSdkVersion flutter.targetSdkVersion + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/pkgs/jnigen/example/notification_plugin/example/android/app/src/debug/AndroidManifest.xml b/pkgs/jnigen/example/notification_plugin/example/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 000000000..822a20815 --- /dev/null +++ b/pkgs/jnigen/example/notification_plugin/example/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,8 @@ + + + + diff --git a/pkgs/jnigen/example/notification_plugin/example/android/app/src/main/AndroidManifest.xml b/pkgs/jnigen/example/notification_plugin/example/android/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..60e7eab80 --- /dev/null +++ b/pkgs/jnigen/example/notification_plugin/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + diff --git a/pkgs/jnigen/example/notification_plugin/example/android/app/src/main/kotlin/com/example/notification_plugin_example/MainActivity.kt b/pkgs/jnigen/example/notification_plugin/example/android/app/src/main/kotlin/com/example/notification_plugin_example/MainActivity.kt new file mode 100644 index 000000000..af88e15d8 --- /dev/null +++ b/pkgs/jnigen/example/notification_plugin/example/android/app/src/main/kotlin/com/example/notification_plugin_example/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.notification_plugin_example + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} diff --git a/pkgs/jnigen/example/notification_plugin/example/android/app/src/main/res/drawable-v21/launch_background.xml b/pkgs/jnigen/example/notification_plugin/example/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 000000000..f74085f3f --- /dev/null +++ b/pkgs/jnigen/example/notification_plugin/example/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/pkgs/jnigen/example/notification_plugin/example/android/app/src/main/res/drawable/launch_background.xml b/pkgs/jnigen/example/notification_plugin/example/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 000000000..304732f88 --- /dev/null +++ b/pkgs/jnigen/example/notification_plugin/example/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/pkgs/jnigen/example/notification_plugin/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/pkgs/jnigen/example/notification_plugin/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..db77bb4b7 Binary files /dev/null and b/pkgs/jnigen/example/notification_plugin/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/pkgs/jnigen/example/notification_plugin/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/pkgs/jnigen/example/notification_plugin/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..17987b79b Binary files /dev/null and b/pkgs/jnigen/example/notification_plugin/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/pkgs/jnigen/example/notification_plugin/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/pkgs/jnigen/example/notification_plugin/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..09d439148 Binary files /dev/null and b/pkgs/jnigen/example/notification_plugin/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/pkgs/jnigen/example/notification_plugin/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/pkgs/jnigen/example/notification_plugin/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..d5f1c8d34 Binary files /dev/null and b/pkgs/jnigen/example/notification_plugin/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/pkgs/jnigen/example/notification_plugin/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/pkgs/jnigen/example/notification_plugin/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..4d6372eeb Binary files /dev/null and b/pkgs/jnigen/example/notification_plugin/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/pkgs/jnigen/example/notification_plugin/example/android/app/src/main/res/values-night/styles.xml b/pkgs/jnigen/example/notification_plugin/example/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 000000000..06952be74 --- /dev/null +++ b/pkgs/jnigen/example/notification_plugin/example/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/pkgs/jnigen/example/notification_plugin/example/android/app/src/main/res/values/styles.xml b/pkgs/jnigen/example/notification_plugin/example/android/app/src/main/res/values/styles.xml new file mode 100644 index 000000000..cb1ef8805 --- /dev/null +++ b/pkgs/jnigen/example/notification_plugin/example/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/pkgs/jnigen/example/notification_plugin/example/android/app/src/profile/AndroidManifest.xml b/pkgs/jnigen/example/notification_plugin/example/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 000000000..822a20815 --- /dev/null +++ b/pkgs/jnigen/example/notification_plugin/example/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,8 @@ + + + + diff --git a/pkgs/jnigen/example/notification_plugin/example/android/build.gradle b/pkgs/jnigen/example/notification_plugin/example/android/build.gradle new file mode 100644 index 000000000..3cdaac958 --- /dev/null +++ b/pkgs/jnigen/example/notification_plugin/example/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.6.10' + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:7.1.2' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +tasks.register("clean", Delete) { + delete rootProject.buildDir +} diff --git a/pkgs/jnigen/example/notification_plugin/example/android/gradle.properties b/pkgs/jnigen/example/notification_plugin/example/android/gradle.properties new file mode 100644 index 000000000..94adc3a3f --- /dev/null +++ b/pkgs/jnigen/example/notification_plugin/example/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true diff --git a/pkgs/jnigen/example/notification_plugin/example/android/gradle/wrapper/gradle-wrapper.properties b/pkgs/jnigen/example/notification_plugin/example/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..cb24abda1 --- /dev/null +++ b/pkgs/jnigen/example/notification_plugin/example/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip diff --git a/pkgs/jnigen/example/notification_plugin/example/android/settings.gradle b/pkgs/jnigen/example/notification_plugin/example/android/settings.gradle new file mode 100644 index 000000000..44e62bcf0 --- /dev/null +++ b/pkgs/jnigen/example/notification_plugin/example/android/settings.gradle @@ -0,0 +1,11 @@ +include ':app' + +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() + +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/pkgs/jnigen/example/notification_plugin/example/lib/main.dart b/pkgs/jnigen/example/notification_plugin/example/lib/main.dart new file mode 100644 index 000000000..c834bcbf2 --- /dev/null +++ b/pkgs/jnigen/example/notification_plugin/example/lib/main.dart @@ -0,0 +1,89 @@ +// 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. + +import 'package:flutter/material.dart'; +import 'package:jni/jni.dart'; + +// The hierarchy created in generated code will mirror the java package +// structure. This is an implementation convenience and we may allow +// more customization in future. +import 'package:notification_plugin/notifications.dart'; + +JObject activity = JObject.fromRef(Jni.getCurrentActivity()); + +int i = 0; + +void showNotification(String title, String text) { + i = i + 1; + var jTitle = JString.fromString(title); + var jText = JString.fromString(text); + Notifications.showNotification(activity, i, jTitle, jText); + jTitle.release(); + jText.release(); +} + +void main() { + runApp(const MyApp()); +} + +class MyApp extends StatelessWidget { + const MyApp({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + theme: ThemeData( + primarySwatch: Colors.teal, + ), + home: MyHomePage(title: 'Flutter Demo Home Page'), + ); + } +} + +class MyHomePage extends StatelessWidget { + MyHomePage({Key? key, required this.title}) : super(key: key); + + final String title; + + final _title = TextEditingController(text: 'Hello from JNI'); + final _text = TextEditingController(text: '😀'); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(title), + ), + body: Center( + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + TextFormField( + controller: _title, + textCapitalization: TextCapitalization.sentences, + decoration: + const InputDecoration(labelText: 'Notification title'), + ), + TextFormField( + controller: _text, + keyboardType: TextInputType.multiline, + minLines: 1, + maxLines: 4, + decoration: + const InputDecoration(labelText: 'Notification text'), + ), + ElevatedButton( + child: const Text('Show Notification'), + onPressed: () => showNotification(_title.text, _text.text), + ), + ], + ), + ), + ), + ); + } +} diff --git a/pkgs/jnigen/example/notification_plugin/example/pubspec.yaml b/pkgs/jnigen/example/notification_plugin/example/pubspec.yaml new file mode 100644 index 000000000..35f3357f1 --- /dev/null +++ b/pkgs/jnigen/example/notification_plugin/example/pubspec.yaml @@ -0,0 +1,89 @@ +name: notification_plugin_example +description: Demonstrates how to use notification_plugin. + +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +# In Windows, build-name is used as the major, minor, and patch parts +# of the product and file versions while build-number is used as the build suffix. +version: 1.0.0+1 + +environment: + sdk: '>=3.1.0 <4.0.0' + +dependencies: + flutter: + sdk: flutter + + notification_plugin: + path: ../ + + jni: + path: ../../../../jni/ + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.2 + +dev_dependencies: + flutter_test: + sdk: flutter + + # The "flutter_lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # activated in the `analysis_options.yaml` file located at the root of your + # package. See that file for information about deactivating specific lint + # rules and activating additional ones. + flutter_lints: ^2.0.0 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/assets-and-images/#from-packages + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/custom-fonts/#from-packages diff --git a/pkgs/jnigen/example/notification_plugin/jnigen.yaml b/pkgs/jnigen/example/notification_plugin/jnigen.yaml new file mode 100644 index 000000000..21f4106f1 --- /dev/null +++ b/pkgs/jnigen/example/notification_plugin/jnigen.yaml @@ -0,0 +1,24 @@ +android_sdk_config: + add_gradle_deps: true + android_example: 'example/' + +preamble: | + // 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. + +source_path: + - 'android/src/main/java' +classes: + - 'com.example.notification_plugin.Notifications' + +output: + c: + path: 'src/' + library_name: notification_plugin + dart: + path: 'lib/notifications.dart' + ## Output to single file instead of recreating source's file structure. + ## This will be useful to reduce clutter when binding a small number of + ## classes. + structure: 'single_file' diff --git a/pkgs/jnigen/example/notification_plugin/lib/notifications.dart b/pkgs/jnigen/example/notification_plugin/lib/notifications.dart new file mode 100644 index 000000000..9855d16ae --- /dev/null +++ b/pkgs/jnigen/example/notification_plugin/lib/notifications.dart @@ -0,0 +1,101 @@ +// 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. + +// Autogenerated by jnigen. DO NOT EDIT! + +// ignore_for_file: annotate_overrides +// ignore_for_file: camel_case_extensions +// ignore_for_file: camel_case_types +// ignore_for_file: constant_identifier_names +// ignore_for_file: file_names +// ignore_for_file: lines_longer_than_80_chars +// ignore_for_file: no_leading_underscores_for_local_identifiers +// ignore_for_file: non_constant_identifier_names +// ignore_for_file: overridden_fields +// ignore_for_file: unnecessary_cast +// ignore_for_file: unused_element +// ignore_for_file: unused_field +// ignore_for_file: unused_import +// ignore_for_file: unused_local_variable +// ignore_for_file: unused_shown_name + +import "dart:isolate" show ReceivePort; +import "dart:ffi" as ffi; +import "package:jni/internal_helpers_for_jnigen.dart"; +import "package:jni/jni.dart" as jni; + +// Auto-generated initialization code. + +final ffi.Pointer Function(String sym) jniLookup = + ProtectedJniExtensions.initGeneratedLibrary("notification_plugin"); + +/// from: com.example.notification_plugin.Notifications +class Notifications extends jni.JObject { + @override + late final jni.JObjType $type = type; + + Notifications.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $NotificationsType(); + static final _new0 = jniLookup>( + "Notifications__new0") + .asFunction(); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory Notifications() { + return Notifications.fromRef(_new0().object); + } + + static final _showNotification = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Int32, + ffi.Pointer, + ffi.Pointer)>>("Notifications__showNotification") + .asFunction< + jni.JniResult Function(ffi.Pointer, int, + ffi.Pointer, ffi.Pointer)>(); + + /// from: static public void showNotification(android.content.Context context, int notificationID, java.lang.String title, java.lang.String text) + static void showNotification( + jni.JObject context, + int notificationID, + jni.JString title, + jni.JString text, + ) { + return _showNotification( + context.reference, notificationID, title.reference, text.reference) + .check(); + } +} + +final class $NotificationsType extends jni.JObjType { + const $NotificationsType(); + + @override + String get signature => r"Lcom/example/notification_plugin/Notifications;"; + + @override + Notifications fromRef(jni.JObjectPtr ref) => Notifications.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($NotificationsType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($NotificationsType) && + other is $NotificationsType; + } +} diff --git a/pkgs/jnigen/example/notification_plugin/pubspec.yaml b/pkgs/jnigen/example/notification_plugin/pubspec.yaml new file mode 100644 index 000000000..1f6cf4925 --- /dev/null +++ b/pkgs/jnigen/example/notification_plugin/pubspec.yaml @@ -0,0 +1,76 @@ +name: notification_plugin +description: Example for Android plugin with custom Java code using jnigen. +version: 0.0.1 +publish_to: none +homepage: https://github.com/dart-lang/jnigen + +environment: + sdk: '>=3.1.0 <4.0.0' + flutter: ">=2.11.0" + +dependencies: + jni: + path: ../../../jni/ + flutter: + sdk: flutter + plugin_platform_interface: ^2.0.2 + +dev_dependencies: + jnigen: + path: ../../ + flutter_test: + sdk: flutter + flutter_lints: ^2.0.0 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + # This section identifies this Flutter project as a plugin project. + # The 'pluginClass' specifies the class (in Java, Kotlin, Swift, Objective-C, etc.) + # which should be registered in the plugin registry. This is required for + # using method channels. + # The Android 'package' specifies package in which the registered class is. + # This is required for using method channels on Android. + # The 'ffiPlugin' specifies that native code should be built and bundled. + # This is required for using `dart:ffi`. + # All these are used by the tooling to maintain consistency when + # adding or updating assets for this project. + # + # Please refer to README.md for a detailed explanation. + plugin: + platforms: + android: + ffiPlugin: true + + # To add assets to your plugin package, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + # + # For details regarding assets in packages, see + # https://flutter.dev/assets-and-images/#from-packages + # + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware + + # To add custom fonts to your plugin package, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts in packages, see + # https://flutter.dev/custom-fonts/#from-packages diff --git a/pkgs/jnigen/example/notification_plugin/src/.clang-format b/pkgs/jnigen/example/notification_plugin/src/.clang-format new file mode 100644 index 000000000..a256c2f09 --- /dev/null +++ b/pkgs/jnigen/example/notification_plugin/src/.clang-format @@ -0,0 +1,15 @@ +# From dart SDK: https://github.com/dart-lang/sdk/blob/main/.clang-format + +# Defines the Chromium style for automatic reformatting. +# http://clang.llvm.org/docs/ClangFormatStyleOptions.html +BasedOnStyle: Chromium + +# clang-format doesn't seem to do a good job of this for longer comments. +ReflowComments: 'false' + +# We have lots of these. Though we need to put them all in curly braces, +# clang-format can't do that. +AllowShortIfStatementsOnASingleLine: 'true' + +# Put escaped newlines into the rightmost column. +AlignEscapedNewlinesLeft: false diff --git a/pkgs/jnigen/example/notification_plugin/src/CMakeLists.txt b/pkgs/jnigen/example/notification_plugin/src/CMakeLists.txt new file mode 100644 index 000000000..39c985034 --- /dev/null +++ b/pkgs/jnigen/example/notification_plugin/src/CMakeLists.txt @@ -0,0 +1,32 @@ +# jni_native_build (Build with jni:setup. Do not delete this line.) + +# The Flutter tooling requires that developers have CMake 3.10 or later +# installed. You should not increase this version, as doing so will cause +# the plugin to fail to compile for some customers of the plugin. +cmake_minimum_required(VERSION 3.10) + +project(notification_plugin VERSION 0.0.1 LANGUAGES C) + +add_library(notification_plugin SHARED + "./notification_plugin.c" +) + +set_target_properties(notification_plugin PROPERTIES + OUTPUT_NAME "notification_plugin" +) + +target_compile_definitions(notification_plugin PUBLIC DART_SHARED_LIB) + +if(WIN32) + set_target_properties(${TARGET_NAME} PROPERTIES + LINK_FLAGS "/DELAYLOAD:jvm.dll") +endif() + +if (ANDROID) + target_link_libraries(notification_plugin log) +else() + find_package(Java REQUIRED) + find_package(JNI REQUIRED) + include_directories(${JNI_INCLUDE_DIRS}) + target_link_libraries(notification_plugin ${JNI_LIBRARIES}) +endif() diff --git a/pkgs/jnigen/example/notification_plugin/src/dartjni.h b/pkgs/jnigen/example/notification_plugin/src/dartjni.h new file mode 100644 index 000000000..8f1dc7481 --- /dev/null +++ b/pkgs/jnigen/example/notification_plugin/src/dartjni.h @@ -0,0 +1,424 @@ +// 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. + +#pragma once + +// Note: include appropriate system jni.h as found by CMake, not third_party/jni.h. +#include +#include +#include +#include + +#if _WIN32 +#include +#else +#include +#include +#endif + +#if _WIN32 +#define FFI_PLUGIN_EXPORT __declspec(dllexport) +#else +#define FFI_PLUGIN_EXPORT +#endif + +#if defined _WIN32 +#define thread_local __declspec(thread) +#else +#define thread_local __thread +#endif + +#ifdef __ANDROID__ +#include +#endif + +#ifdef __ANDROID__ +#define __ENVP_CAST (JNIEnv**) +#else +#define __ENVP_CAST (void**) +#endif + +/// Locking functions for windows and pthread. + +#if defined _WIN32 +#include + +typedef CRITICAL_SECTION MutexLock; +typedef CONDITION_VARIABLE ConditionVariable; + +static inline void init_lock(MutexLock* lock) { + InitializeCriticalSection(lock); +} + +static inline void acquire_lock(MutexLock* lock) { + EnterCriticalSection(lock); +} + +static inline void release_lock(MutexLock* lock) { + LeaveCriticalSection(lock); +} + +static inline void destroy_lock(MutexLock* lock) { + DeleteCriticalSection(lock); +} + +static inline void init_cond(ConditionVariable* cond) { + InitializeConditionVariable(cond); +} + +static inline void signal_cond(ConditionVariable* cond) { + WakeConditionVariable(cond); +} + +static inline void wait_for(ConditionVariable* cond, MutexLock* lock) { + SleepConditionVariableCS(cond, lock, INFINITE); +} + +static inline void destroy_cond(ConditionVariable* cond) { + // Not available. +} + +#elif defined __APPLE__ || defined __LINUX__ || defined __ANDROID__ || \ + defined __GNUC__ +#include + +typedef pthread_mutex_t MutexLock; +typedef pthread_cond_t ConditionVariable; + +static inline void init_lock(MutexLock* lock) { + pthread_mutex_init(lock, NULL); +} + +static inline void acquire_lock(MutexLock* lock) { + pthread_mutex_lock(lock); +} + +static inline void release_lock(MutexLock* lock) { + pthread_mutex_unlock(lock); +} + +static inline void destroy_lock(MutexLock* lock) { + pthread_mutex_destroy(lock); +} + +static inline void init_cond(ConditionVariable* cond) { + pthread_cond_init(cond, NULL); +} + +static inline void signal_cond(ConditionVariable* cond) { + pthread_cond_signal(cond); +} + +static inline void wait_for(ConditionVariable* cond, MutexLock* lock) { + pthread_cond_wait(cond, lock); +} + +static inline void destroy_cond(ConditionVariable* cond) { + pthread_cond_destroy(cond); +} + +#else + +#error "No locking/condition variable support; Possibly unsupported platform" + +#endif + +typedef struct CallbackResult { + MutexLock lock; + ConditionVariable cond; + int ready; + jobject object; +} CallbackResult; + +typedef struct JniLocks { + MutexLock classLoadingLock; + MutexLock methodLoadingLock; + MutexLock fieldLoadingLock; +} JniLocks; + +/// Represents the error when dart-jni layer has already spawned singleton VM. +#define DART_JNI_SINGLETON_EXISTS (-99); + +/// Stores the global state of the JNI. +typedef struct JniContext { + JavaVM* jvm; + jobject classLoader; + jmethodID loadClassMethod; + jobject currentActivity; + jobject appContext; + JniLocks locks; +} JniContext; + +// jniEnv for this thread, used by inline functions in this header, +// therefore declared as extern. +extern thread_local JNIEnv* jniEnv; + +extern JniContext* jni; + +/// Types used by JNI API to distinguish between primitive types. +enum JniType { + booleanType = 0, + byteType = 1, + shortType = 2, + charType = 3, + intType = 4, + longType = 5, + floatType = 6, + doubleType = 7, + objectType = 8, + voidType = 9, +}; + +/// Result type for use by JNI. +/// +/// If [exception] is null, it means the result is valid. +/// It's assumed that the caller knows the expected type in [result]. +typedef struct JniResult { + jvalue value; + jthrowable exception; +} JniResult; + +/// Similar to [JniResult] but for class lookups. +typedef struct JniClassLookupResult { + jclass value; + jthrowable exception; +} JniClassLookupResult; + +/// Similar to [JniResult] but for method/field ID lookups. +typedef struct JniPointerResult { + const void* value; + jthrowable exception; +} JniPointerResult; + +/// JniExceptionDetails holds 2 jstring objects, one is the result of +/// calling `toString` on exception object, other is stack trace; +typedef struct JniExceptionDetails { + jstring message; + jstring stacktrace; +} JniExceptionDetails; + +/// This struct contains functions which wrap method call / field access conveniently along with +/// exception checking. +/// +/// Flutter embedding checks for pending JNI exceptions before an FFI transition, which requires us +/// to check for and clear the exception before returning to dart code, which requires these functions +/// to return result types. +typedef struct JniAccessorsStruct { + JniClassLookupResult (*getClass)(char* internalName); + JniPointerResult (*getFieldID)(jclass cls, char* fieldName, char* signature); + JniPointerResult (*getStaticFieldID)(jclass cls, + char* fieldName, + char* signature); + JniPointerResult (*getMethodID)(jclass cls, + char* methodName, + char* signature); + JniPointerResult (*getStaticMethodID)(jclass cls, + char* methodName, + char* signature); + JniResult (*newObject)(jclass cls, jmethodID ctor, jvalue* args); + JniResult (*newPrimitiveArray)(jsize length, int type); + JniResult (*newObjectArray)(jsize length, + jclass elementClass, + jobject initialElement); + JniResult (*getArrayElement)(jarray array, int index, int type); + JniResult (*callMethod)(jobject obj, + jmethodID methodID, + int callType, + jvalue* args); + JniResult (*callStaticMethod)(jclass cls, + jmethodID methodID, + int callType, + jvalue* args); + JniResult (*getField)(jobject obj, jfieldID fieldID, int callType); + JniResult (*getStaticField)(jclass cls, jfieldID fieldID, int callType); + JniExceptionDetails (*getExceptionDetails)(jthrowable exception); +} JniAccessorsStruct; + +FFI_PLUGIN_EXPORT JniAccessorsStruct* GetAccessors(); + +FFI_PLUGIN_EXPORT JavaVM* GetJavaVM(void); + +FFI_PLUGIN_EXPORT JNIEnv* GetJniEnv(void); + +/// Spawn a JVM with given arguments. +/// +/// Returns JNI_OK on success, and one of the documented JNI error codes on +/// failure. It returns DART_JNI_SINGLETON_EXISTS if an attempt to spawn multiple +/// JVMs is made, even if the underlying API potentially supports multiple VMs. +FFI_PLUGIN_EXPORT int SpawnJvm(JavaVMInitArgs* args); + +/// Load class through platform-specific mechanism. +/// +/// Currently uses application classloader on android, +/// and JNIEnv->FindClass on other platforms. +FFI_PLUGIN_EXPORT jclass FindClass(const char* name); + +/// Returns Application classLoader (on Android), +/// which can be used to load application and platform classes. +/// +/// On other platforms, NULL is returned. +FFI_PLUGIN_EXPORT jobject GetClassLoader(void); + +/// Returns application context on Android. +/// +/// On other platforms, NULL is returned. +FFI_PLUGIN_EXPORT jobject GetApplicationContext(void); + +/// Returns current activity of the app on Android. +FFI_PLUGIN_EXPORT jobject GetCurrentActivity(void); + +static inline void attach_thread() { + if (jniEnv == NULL) { + (*jni->jvm)->AttachCurrentThread(jni->jvm, __ENVP_CAST & jniEnv, NULL); + } +} + +/// Load class into [cls] using platform specific mechanism +static inline void load_class_platform(jclass* cls, const char* name) { +#ifdef __ANDROID__ + jstring className = (*jniEnv)->NewStringUTF(jniEnv, name); + *cls = (*jniEnv)->CallObjectMethod(jniEnv, jni->classLoader, + jni->loadClassMethod, className); + (*jniEnv)->DeleteLocalRef(jniEnv, className); +#else + *cls = (*jniEnv)->FindClass(jniEnv, name); +#endif +} + +static inline void load_class_local_ref(jclass* cls, const char* name) { + if (*cls == NULL) { + acquire_lock(&jni->locks.classLoadingLock); + if (*cls == NULL) { + load_class_platform(cls, name); + } + release_lock(&jni->locks.classLoadingLock); + } +} + +static inline void load_class_global_ref(jclass* cls, const char* name) { + if (*cls == NULL) { + jclass tmp = NULL; + acquire_lock(&jni->locks.classLoadingLock); + if (*cls == NULL) { + load_class_platform(&tmp, name); + if (!(*jniEnv)->ExceptionCheck(jniEnv)) { + *cls = (*jniEnv)->NewGlobalRef(jniEnv, tmp); + (*jniEnv)->DeleteLocalRef(jniEnv, tmp); + } + } + release_lock(&jni->locks.classLoadingLock); + } +} + +static inline void load_method(jclass cls, + jmethodID* res, + const char* name, + const char* sig) { + if (*res == NULL) { + acquire_lock(&jni->locks.methodLoadingLock); + if (*res == NULL) { + *res = (*jniEnv)->GetMethodID(jniEnv, cls, name, sig); + } + release_lock(&jni->locks.methodLoadingLock); + } +} + +static inline void load_static_method(jclass cls, + jmethodID* res, + const char* name, + const char* sig) { + if (*res == NULL) { + acquire_lock(&jni->locks.methodLoadingLock); + if (*res == NULL) { + *res = (*jniEnv)->GetStaticMethodID(jniEnv, cls, name, sig); + } + release_lock(&jni->locks.methodLoadingLock); + } +} + +static inline void load_field(jclass cls, + jfieldID* res, + const char* name, + const char* sig) { + if (*res == NULL) { + acquire_lock(&jni->locks.fieldLoadingLock); + if (*res == NULL) { + *res = (*jniEnv)->GetFieldID(jniEnv, cls, name, sig); + } + release_lock(&jni->locks.fieldLoadingLock); + } +} + +static inline void load_static_field(jclass cls, + jfieldID* res, + const char* name, + const char* sig) { + if (*res == NULL) { + acquire_lock(&jni->locks.fieldLoadingLock); + if (*res == NULL) { + *res = (*jniEnv)->GetStaticFieldID(jniEnv, cls, name, sig); + } + release_lock(&jni->locks.fieldLoadingLock); + } +} + +static inline jobject to_global_ref(jobject ref) { + jobject g = (*jniEnv)->NewGlobalRef(jniEnv, ref); + (*jniEnv)->DeleteLocalRef(jniEnv, ref); + return g; +} + +// These functions are useful for C+Dart bindings, and not required for pure dart bindings. + +FFI_PLUGIN_EXPORT JniContext* GetJniContextPtr(); + +/// For use by jni_gen's generated code +/// don't use these. + +// these 2 fn ptr vars will be defined by generated code library +extern JniContext* (*context_getter)(void); +extern JNIEnv* (*env_getter)(void); + +// this function will be exported by generated code library +// it will set above 2 variables. +FFI_PLUGIN_EXPORT void setJniGetters(struct JniContext* (*cg)(void), + JNIEnv* (*eg)(void)); + +static inline void load_env() { + if (jniEnv == NULL) { + jni = context_getter(); + jniEnv = env_getter(); + } +} + +static inline jthrowable check_exception() { + jthrowable exception = (*jniEnv)->ExceptionOccurred(jniEnv); + if (exception != NULL) (*jniEnv)->ExceptionClear(jniEnv); + if (exception == NULL) return NULL; + return to_global_ref(exception); +} + +static inline JniResult to_global_ref_result(jobject ref) { + JniResult result; + result.exception = check_exception(); + if (result.exception == NULL) { + result.value.l = to_global_ref(ref); + } + return result; +} + +FFI_PLUGIN_EXPORT intptr_t InitDartApiDL(void* data); + +FFI_PLUGIN_EXPORT +JniResult DartException__ctor(jstring message); + +FFI_PLUGIN_EXPORT +JniResult PortContinuation__ctor(int64_t j); + +FFI_PLUGIN_EXPORT +JniResult PortProxy__newInstance(jobject binaryName, + int64_t port, + int64_t functionPtr); + +FFI_PLUGIN_EXPORT void resultFor(CallbackResult* result, jobject object); diff --git a/pkgs/jnigen/example/notification_plugin/src/notification_plugin.c b/pkgs/jnigen/example/notification_plugin/src/notification_plugin.c new file mode 100644 index 000000000..9f1e57745 --- /dev/null +++ b/pkgs/jnigen/example/notification_plugin/src/notification_plugin.c @@ -0,0 +1,61 @@ +// 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. + +// Autogenerated by jnigen. DO NOT EDIT! + +#include +#include "dartjni.h" +#include "jni.h" + +thread_local JNIEnv* jniEnv; +JniContext* jni; + +JniContext* (*context_getter)(void); +JNIEnv* (*env_getter)(void); + +void setJniGetters(JniContext* (*cg)(void), JNIEnv* (*eg)(void)) { + context_getter = cg; + env_getter = eg; +} + +// com.example.notification_plugin.Notifications +jclass _c_Notifications = NULL; + +jmethodID _m_Notifications__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult Notifications__new0() { + load_env(); + load_class_global_ref(&_c_Notifications, + "com/example/notification_plugin/Notifications"); + if (_c_Notifications == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Notifications, &_m_Notifications__new0, "", "()V"); + if (_m_Notifications__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->NewObject(jniEnv, _c_Notifications, _m_Notifications__new0); + return to_global_ref_result(_result); +} + +jmethodID _m_Notifications__showNotification = NULL; +FFI_PLUGIN_EXPORT +JniResult Notifications__showNotification(jobject context, + int32_t notificationID, + jobject title, + jobject text) { + load_env(); + load_class_global_ref(&_c_Notifications, + "com/example/notification_plugin/Notifications"); + if (_c_Notifications == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method( + _c_Notifications, &_m_Notifications__showNotification, "showNotification", + "(Landroid/content/Context;ILjava/lang/String;Ljava/lang/String;)V"); + if (_m_Notifications__showNotification == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallStaticVoidMethod(jniEnv, _c_Notifications, + _m_Notifications__showNotification, context, + notificationID, title, text); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} diff --git a/pkgs/jnigen/example/pdfbox_plugin/.gitignore b/pkgs/jnigen/example/pdfbox_plugin/.gitignore new file mode 100644 index 000000000..a117acd0b --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/.gitignore @@ -0,0 +1,42 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +.packages +build/ + +## Downloaded by jnigen +/mvn_java/ +/mvn_jar/ +## Sometimes generated by maven. +## TODO(#34) This is unwanted. +/target/ + +# Builds & downloads +*.pdf +*.jar +*.exe diff --git a/pkgs/jnigen/example/pdfbox_plugin/.metadata b/pkgs/jnigen/example/pdfbox_plugin/.metadata new file mode 100644 index 000000000..9d23aa995 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/.metadata @@ -0,0 +1,36 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled. + +version: + revision: f1875d570e39de09040c8f79aa13cc56baab8db1 + channel: stable + +project_type: plugin_ffi + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 + base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 + - platform: android + create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 + base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 + - platform: linux + create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 + base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 + - platform: windows + create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 + base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/pkgs/jnigen/example/pdfbox_plugin/README.md b/pkgs/jnigen/example/pdfbox_plugin/README.md new file mode 100644 index 000000000..efa8caa40 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/README.md @@ -0,0 +1,8 @@ +# pdfbox_plugin + +Example of a JNI plugin using `jnigen` to auto-generate bindings for PDFBox java library. + +Bindings can be generated by running `dart run jnigen --config jnigen.yaml`. Required source code and JARs will be downloaded using maven (requires `mvn` command). + +`jnigen` is also available as an API which tooling scripts can use. See `tool/generate_bindings.dart` for the script equivalent of the YAML file. + diff --git a/pkgs/jnigen/example/pdfbox_plugin/analysis_options.yaml b/pkgs/jnigen/example/pdfbox_plugin/analysis_options.yaml new file mode 100644 index 000000000..198e7e069 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/analysis_options.yaml @@ -0,0 +1,4 @@ +#include: package:flutter_lints/flutter.yaml + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/pkgs/jnigen/example/pdfbox_plugin/android/.gitignore b/pkgs/jnigen/example/pdfbox_plugin/android/.gitignore new file mode 100644 index 000000000..161bdcdaf --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/android/.gitignore @@ -0,0 +1,9 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures +.cxx diff --git a/pkgs/jnigen/example/pdfbox_plugin/android/build.gradle b/pkgs/jnigen/example/pdfbox_plugin/android/build.gradle new file mode 100644 index 000000000..9c3bca816 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/android/build.gradle @@ -0,0 +1,59 @@ +// The Android Gradle Plugin builds the native code with the Android NDK. + +group 'com.example.pdfbox_plugin' +version '1.0' + +buildscript { + repositories { + google() + mavenCentral() + } + + dependencies { + // The Android Gradle Plugin knows how to build native code with the NDK. + classpath 'com.android.tools.build:gradle:7.1.2' + } +} + +rootProject.allprojects { + repositories { + google() + mavenCentral() + } +} + +apply plugin: 'com.android.library' + +android { + // Bumping the plugin compileSdkVersion requires all clients of this plugin + // to bump the version in their app. + compileSdkVersion 31 + + // Bumping the plugin ndkVersion requires all clients of this plugin to bump + // the version in their app and to download a newer version of the NDK. + ndkVersion "21.1.6352462" + + // Invoke the shared CMake build with the Android Gradle Plugin. + externalNativeBuild { + cmake { + path "../src/CMakeLists.txt" + + // The default CMake version for the Android Gradle Plugin is 3.10.2. + // https://developer.android.com/studio/projects/install-ndk#vanilla_cmake + // + // The Flutter tooling requires that developers have CMake 3.10 or later + // installed. You should not increase this version, as doing so will cause + // the plugin to fail to compile for some customers of the plugin. + // version "3.10.2" + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + defaultConfig { + minSdkVersion 16 + } +} diff --git a/pkgs/jnigen/example/pdfbox_plugin/android/settings.gradle b/pkgs/jnigen/example/pdfbox_plugin/android/settings.gradle new file mode 100644 index 000000000..84ca2f9e4 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/android/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'pdfbox_plugin' diff --git a/pkgs/jnigen/example/pdfbox_plugin/android/src/main/AndroidManifest.xml b/pkgs/jnigen/example/pdfbox_plugin/android/src/main/AndroidManifest.xml new file mode 100644 index 000000000..ae0f6a3f4 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/android/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ + + diff --git a/pkgs/jnigen/example/pdfbox_plugin/dart_example/.gitignore b/pkgs/jnigen/example/pdfbox_plugin/dart_example/.gitignore new file mode 100644 index 000000000..96449441d --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/dart_example/.gitignore @@ -0,0 +1,12 @@ +# Files and directories created by pub. +.dart_tool/ +.packages + +# Conventional directory for build output. +build/ + +# PDF files +*.pdf + +# AOT compiled +*.exe diff --git a/pkgs/jnigen/example/pdfbox_plugin/dart_example/CHANGELOG.md b/pkgs/jnigen/example/pdfbox_plugin/dart_example/CHANGELOG.md new file mode 100644 index 000000000..effe43c82 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/dart_example/CHANGELOG.md @@ -0,0 +1,3 @@ +## 1.0.0 + +- Initial version. diff --git a/pkgs/jnigen/example/pdfbox_plugin/dart_example/README.md b/pkgs/jnigen/example/pdfbox_plugin/dart_example/README.md new file mode 100644 index 000000000..6a6755e0f --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/dart_example/README.md @@ -0,0 +1,10 @@ +## Running +After generating `pdfbox_plugin` bindings in the parent directory + +* setup native libraries: `dart run jni:setup` + +* `dart run bin/pdf_info.dart ` + +Alternatively, it's possible to compile `bin/pdf_info.dart` and then run it. + +To run it from other directories, the `helperDir` and `classpath` parameters in `Jni.spawn` call should be adjusted appropriately. diff --git a/pkgs/jnigen/example/pdfbox_plugin/dart_example/analysis_options.yaml b/pkgs/jnigen/example/pdfbox_plugin/dart_example/analysis_options.yaml new file mode 100644 index 000000000..dee8927aa --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/dart_example/analysis_options.yaml @@ -0,0 +1,30 @@ +# This file configures the static analysis results for your project (errors, +# warnings, and lints). +# +# This enables the 'recommended' set of lints from `package:lints`. +# This set helps identify many issues that may lead to problems when running +# or consuming Dart code, and enforces writing Dart using a single, idiomatic +# style and format. +# +# If you want a smaller set of lints you can change this to specify +# 'package:lints/core.yaml'. These are just the most critical lints +# (the recommended set includes the core lints). +# The core lints are also what is used by pub.dev for scoring packages. + +include: package:lints/recommended.yaml + +# Uncomment the following section to specify additional rules. + +# linter: +# rules: +# - camel_case_types + +# analyzer: +# exclude: +# - path/to/excluded/files/** + +# For more information about the core and recommended set of lints, see +# https://dart.dev/go/core-lints + +# For additional information about configuring this file, see +# https://dart.dev/guides/language/analysis-options diff --git a/pkgs/jnigen/example/pdfbox_plugin/dart_example/bin/pdf_info.dart b/pkgs/jnigen/example/pdfbox_plugin/dart_example/bin/pdf_info.dart new file mode 100644 index 000000000..5dfd5851c --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/dart_example/bin/pdf_info.dart @@ -0,0 +1,70 @@ +// 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. + +import 'dart:io'; + +import 'package:path/path.dart'; +import 'package:jni/jni.dart'; + +import 'package:pdfbox_plugin/pdfbox_plugin.dart'; + +void writeInfo(String file) { + final inputFile = Jni.newInstance( + "java/io/FileInputStream", "(Ljava/lang/String;)V", [file]); + final pdDoc = PDDocument.load6(inputFile); + int pages = pdDoc.getNumberOfPages(); + final info = pdDoc.getDocumentInformation(); + final title = info.getTitle(); + final subject = info.getSubject(); + final author = info.getAuthor(); + stderr.writeln('Number of pages: $pages'); + + if (!title.isNull) { + stderr.writeln('Title: ${title.toDartString()}'); + } + + if (!subject.isNull) { + stderr.writeln('Subject: ${subject.toDartString()}'); + } + + if (!author.isNull) { + stderr.writeln('Author: ${author.toDartString()}'); + } + + stderr.writeln('PDF Version: ${pdDoc.getVersion().toStringAsPrecision(2)}'); +} + +final jniLibsDir = join('build', 'jni_libs'); + +const jarError = 'No JAR files were found.\n' + 'Run `dart run jnigen:download_maven_jars --config jnigen.yaml` ' + 'in plugin directory.\n' + 'Alternatively, regenerate JNI bindings in plugin directory, which will ' + 'automatically download the JAR files.'; + +void main(List arguments) { + final jarDir = join('..', 'mvn_jar'); + List jars; + try { + jars = Directory(jarDir) + .listSync() + .map((e) => e.path) + .where((path) => path.endsWith('.jar')) + .toList(); + } on OSError catch (_) { + stderr.writeln(jarError); + return; + } + if (jars.isEmpty) { + stderr.writeln(jarError); + return; + } + Jni.spawn(dylibDir: jniLibsDir, classPath: jars); + if (arguments.length != 1) { + stderr.writeln('usage: dart run pdf_info:pdf_info '); + exitCode = 1; + return; + } + writeInfo(arguments[0]); +} diff --git a/pkgs/jnigen/example/pdfbox_plugin/dart_example/pubspec.yaml b/pkgs/jnigen/example/pdfbox_plugin/dart_example/pubspec.yaml new file mode 100644 index 000000000..4af3cf1fd --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/dart_example/pubspec.yaml @@ -0,0 +1,19 @@ +name: pdf_info +description: Dart standalone example using jnigen PDFBox bindings. +version: 1.0.0 +publish_to: none +# homepage: https://www.example.com + +environment: + sdk: '>=3.1.0 <4.0.0' + +dependencies: + path: ^1.8.0 + jni: + path: ../../../../jni/ + pdfbox_plugin: + path: ../ + +dev_dependencies: + lints: ^2.0.0 + test: ^1.16.0 diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/.gitignore b/pkgs/jnigen/example/pdfbox_plugin/example/.gitignore new file mode 100644 index 000000000..a8e938c08 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/.gitignore @@ -0,0 +1,47 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/README.md b/pkgs/jnigen/example/pdfbox_plugin/example/README.md new file mode 100644 index 000000000..0f471bec6 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/README.md @@ -0,0 +1,18 @@ +# pdfbox_plugin_example + +Demonstrates how to use the PDFBox bindings generated using `jnigen`. This is a Linux Flutter application. The sample application lists the PDF files in a directory with number of pages and title, also allowing to navigate between directories. + +First, it's required to have generated the dart and C bindings in the plugin directory, which also downloads the required JARs using maven. The bindings are not committed because generated code is several thousands of lines. + +On a Linux machine, following commands can be used to run the example application. + +``` +cd .. ## From this folder +dart run jnigen --config jnigen.yaml ## Downloads PDFBox JARs and generates bindings. +cd example/ +flutter run --release ## Opens the files list from home directory +``` + +It may take some time for PDFBox to process all PDFs in a directory. In the interest of simplicity, this example application displays the list after all PDFs are processed. + +Follow along the code in `lib/main.dart` to see how generated bindings are used. diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/analysis_options.yaml b/pkgs/jnigen/example/pdfbox_plugin/example/analysis_options.yaml new file mode 100644 index 000000000..61b6c4de1 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/analysis_options.yaml @@ -0,0 +1,29 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/android/.gitignore b/pkgs/jnigen/example/pdfbox_plugin/example/android/.gitignore new file mode 100644 index 000000000..6f568019d --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/android/.gitignore @@ -0,0 +1,13 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties +**/*.keystore +**/*.jks diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/android/app/build.gradle b/pkgs/jnigen/example/pdfbox_plugin/example/android/app/build.gradle new file mode 100644 index 000000000..c5791ba99 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/android/app/build.gradle @@ -0,0 +1,71 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new FileNotFoundException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion flutter.compileSdkVersion + ndkVersion flutter.ndkVersion + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.pdfbox_plugin_example" + // You can update the following values to match your application needs. + // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration. + minSdkVersion flutter.minSdkVersion + targetSdkVersion flutter.targetSdkVersion + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/debug/AndroidManifest.xml b/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 000000000..3789e50b1 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,8 @@ + + + + diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/main/AndroidManifest.xml b/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..a46900acc --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/main/kotlin/com/example/pdfbox_plugin_example/MainActivity.kt b/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/main/kotlin/com/example/pdfbox_plugin_example/MainActivity.kt new file mode 100644 index 000000000..68d076ced --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/main/kotlin/com/example/pdfbox_plugin_example/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.pdfbox_plugin_example + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/main/res/drawable-v21/launch_background.xml b/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 000000000..f74085f3f --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/main/res/drawable/launch_background.xml b/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 000000000..304732f88 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..db77bb4b7 Binary files /dev/null and b/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..17987b79b Binary files /dev/null and b/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..09d439148 Binary files /dev/null and b/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..d5f1c8d34 Binary files /dev/null and b/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..4d6372eeb Binary files /dev/null and b/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/main/res/values-night/styles.xml b/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 000000000..06952be74 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/main/res/values/styles.xml b/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/main/res/values/styles.xml new file mode 100644 index 000000000..cb1ef8805 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/profile/AndroidManifest.xml b/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 000000000..3789e50b1 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,8 @@ + + + + diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/android/build.gradle b/pkgs/jnigen/example/pdfbox_plugin/example/android/build.gradle new file mode 100644 index 000000000..3cdaac958 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.6.10' + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:7.1.2' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +tasks.register("clean", Delete) { + delete rootProject.buildDir +} diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/android/gradle.properties b/pkgs/jnigen/example/pdfbox_plugin/example/android/gradle.properties new file mode 100644 index 000000000..94adc3a3f --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/android/gradle/wrapper/gradle-wrapper.properties b/pkgs/jnigen/example/pdfbox_plugin/example/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..cc5527d78 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/android/settings.gradle b/pkgs/jnigen/example/pdfbox_plugin/example/android/settings.gradle new file mode 100644 index 000000000..44e62bcf0 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/android/settings.gradle @@ -0,0 +1,11 @@ +include ':app' + +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() + +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/lib/main.dart b/pkgs/jnigen/example/pdfbox_plugin/example/lib/main.dart new file mode 100644 index 000000000..ccc656335 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/lib/main.dart @@ -0,0 +1,202 @@ +// 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. + +import 'package:flutter/material.dart'; +import 'dart:io'; +import 'dart:async'; + +import 'package:jni/jni.dart'; +import 'package:path/path.dart'; + +import 'package:pdfbox_plugin/pdfbox_plugin.dart'; + +Stream files(String dir) => Directory(dir).list().map((e) => e.path); + +const jarError = 'No JAR files were found.\n' + 'Run `dart run jnigen:download_maven_jars --config jnigen.yaml` ' + 'in plugin directory.\n' + 'Alternatively, regenerate JNI bindings in plugin directory, which will ' + 'automatically download the JAR files.'; + +void main() { + if (!Platform.isAndroid) { + // Assuming application is run from example/ folder + // It's required to manually provide the JAR files as classpath when + // spawning the JVM. + const jarDir = '../mvn_jar/'; + List jars; + try { + jars = Directory(jarDir) + .listSync() + .map((e) => e.path) + .where((path) => path.endsWith('.jar')) + .toList(); + } on OSError catch (_) { + stderr.writeln(jarError); + return; + } + if (jars.isEmpty) { + stderr.writeln(jarError); + return; + } + Jni.spawn(classPath: jars); + } + runApp(const PDFInfoApp()); +} + +class PDFInfoApp extends StatefulWidget { + const PDFInfoApp({super.key}); + + @override + PDFInfoAppState createState() => PDFInfoAppState(); +} + +class PDFInfoAppState extends State { + bool _isLoading = true; + String _dir = '.'; + List _pdfs = []; + List _dirs = []; + + void setDir(String dir) async { + final pdfs = []; + final dirs = []; + + setState(() => _isLoading = true); + + await for (var item in Directory(dir).list()) { + final isDir = (await item.stat()).type == FileSystemEntityType.directory; + if (item.path.endsWith('.pdf') && !isDir) { + pdfs.add(item.path); + } else if (isDir) { + dirs.add(item.path); + } + } + setState(() { + _isLoading = false; + _dir = dir; + _pdfs = pdfs; + _dirs = dirs; + }); + } + + @override + void initState() { + super.initState(); + final dir = Platform.environment['HOME'] ?? '.'; + setDir(dir); + } + + @override + Widget build(BuildContext context) { + final dirBaseName = basename(_dir); + return MaterialApp( + home: Scaffold( + appBar: AppBar( + title: Text('PDF Info: $dirBaseName'), + ), + body: SingleChildScrollView( + child: Container( + padding: const EdgeInsets.all(10), + child: _isLoading + ? const Text('loading...') + : Table(border: TableBorder.all(), children: [ + TableRow(children: [ + for (var heading in ['File', 'Title', 'Pages']) + TableCell( + child: _pad(Text(heading, + style: const TextStyle( + fontSize: 16, + decoration: TextDecoration.underline)))), + ]), + TableRow(children: [ + TableCell( + child: _pad( + InkWell( + child: const Text('..'), + onTap: () => setDir(dirname(_dir)), + ), + ), + ), + const TableCell(child: Text('')), + const TableCell(child: Text('')), + ]), + for (var dir in _dirs) _dirTile(basename(dir)), + for (var pdfname in _pdfs) + _pdfInfo(PDFFileInfo.usingPDFBox(pdfname)), + ])), + ), + ), + ); + } + + TableRow _dirTile(String target) { + return TableRow(children: [ + TableCell( + child: _pad( + InkWell( + onTap: () => setDir(join(_dir, target)), + child: Text( + target, + style: const TextStyle(fontWeight: FontWeight.bold), + ), + ), + ), + ), + const TableCell(child: Text('-')), + const TableCell(child: Text('-')), + ]); + } +} + +// It's generally a good practice to separate JNI calls from UI / model code. +class PDFFileInfo { + String filename; + late String author, subject, title; + late int numPages; + + /// Converts JString to dart string and deletes the original. + /// Also handles the case where the underlying string is Null. + String _fromJavaStr(JString jstr) { + if (jstr.reference == nullptr) { + return '(null)'; + } + return jstr.toDartString(releaseOriginal: true); + } + + PDFFileInfo.usingPDFBox(this.filename) { + // Since java.io is not directly available, use package:jni API to + // create a java.io.File object. + final inputFile = + Jni.newInstance("java/io/File", "(Ljava/lang/String;)V", [filename]); + // Static method call PDDocument.load -> PDDocument + final pdf = PDDocument.load(inputFile); + // Instance method call getNumberOfPages() -> int + numPages = pdf.getNumberOfPages(); + // Instance method that returns an object + final info = pdf.getDocumentInformation(); + + /// java.lang.String is a special case and is mapped to JlString which is + /// a subclass of JlObject. + author = _fromJavaStr(info.getAuthor()); + title = _fromJavaStr(info.getTitle()); + subject = _fromJavaStr(info.getSubject()); + + pdf.close(); + } +} + +Padding _pad(Widget w) => Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: w); + +TableRow _pdfInfo(PDFFileInfo info) { + return TableRow(children: [ + TableCell( + child: _pad(Text(basename(info.filename), + style: const TextStyle(fontWeight: FontWeight.bold)))), + TableCell(child: _pad(Text(info.title))), + TableCell( + child: _pad(Text(info.numPages.toString(), + style: const TextStyle(color: Colors.grey)))), + ]); +} diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/linux/.gitignore b/pkgs/jnigen/example/pdfbox_plugin/example/linux/.gitignore new file mode 100644 index 000000000..d3896c984 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/linux/CMakeLists.txt b/pkgs/jnigen/example/pdfbox_plugin/example/linux/CMakeLists.txt new file mode 100644 index 000000000..f36768d83 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/linux/CMakeLists.txt @@ -0,0 +1,138 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.10) +project(runner LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "pdfbox_plugin_example") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "com.example.pdfbox_plugin") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Root filesystem for cross-building. +if(FLUTTER_TARGET_PLATFORM_SYSROOT) + set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +endif() + +# Define build configuration options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Define the application target. To change its name, change BINARY_NAME above, +# not the value here, or `flutter run` will no longer work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# correctly, since the resources must in the right relative locations. To avoid +# people trying to run the unbundled copy, put it in a subdirectory instead of +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/linux/flutter/CMakeLists.txt b/pkgs/jnigen/example/pdfbox_plugin/example/linux/flutter/CMakeLists.txt new file mode 100644 index 000000000..d5bd01648 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/linux/flutter/generated_plugin_registrant.cc b/pkgs/jnigen/example/pdfbox_plugin/example/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 000000000..e71a16d23 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void fl_register_plugins(FlPluginRegistry* registry) { +} diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/linux/flutter/generated_plugin_registrant.h b/pkgs/jnigen/example/pdfbox_plugin/example/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 000000000..e0f0a47bc --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/linux/flutter/generated_plugins.cmake b/pkgs/jnigen/example/pdfbox_plugin/example/linux/flutter/generated_plugins.cmake new file mode 100644 index 000000000..d2cbe738d --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/linux/flutter/generated_plugins.cmake @@ -0,0 +1,25 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST + jni + pdfbox_plugin +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/linux/main.cc b/pkgs/jnigen/example/pdfbox_plugin/example/linux/main.cc new file mode 100644 index 000000000..e7c5c5437 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/linux/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/linux/my_application.cc b/pkgs/jnigen/example/pdfbox_plugin/example/linux/my_application.cc new file mode 100644 index 000000000..b13351b69 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/linux/my_application.cc @@ -0,0 +1,104 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // Use a header bar when running in GNOME as this is the common style used + // by applications and is the setup most users will be using (e.g. Ubuntu + // desktop). + // If running on X and not using GNOME then just use a traditional title bar + // in case the window manager does more exotic layout, e.g. tiling. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "pdfbox_plugin_example"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "pdfbox_plugin_example"); + } + + gtk_window_set_default_size(window, 1280, 720); + gtk_widget_show(GTK_WIDGET(window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, + nullptr)); +} diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/linux/my_application.h b/pkgs/jnigen/example/pdfbox_plugin/example/linux/my_application.h new file mode 100644 index 000000000..72271d5e4 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/linux/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/pubspec.yaml b/pkgs/jnigen/example/pdfbox_plugin/example/pubspec.yaml new file mode 100644 index 000000000..13d0df00f --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/pubspec.yaml @@ -0,0 +1,99 @@ +name: pdfbox_example +description: Demonstrates how to use pdfbox_plugin. + +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +version: 1.0.0+1 + +environment: + sdk: '>=3.1.0 <4.0.0' + +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. +dependencies: + flutter: + sdk: flutter + + jni: + path: ../../../../jni/ + path: ^1.8.0 + pdfbox_plugin: + # When depending on this package from a real application you should use: + # pdfbox_plugin: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. + path: ../ + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.2 + +dev_dependencies: + flutter_test: + sdk: flutter + + # The "flutter_lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # activated in the `analysis_options.yaml` file located at the root of your + # package. See that file for information about deactivating specific lint + # rules and activating additional ones. + flutter_lints: ^2.0.0 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/assets-and-images/#from-packages + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/custom-fonts/#from-packages diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/windows/.gitignore b/pkgs/jnigen/example/pdfbox_plugin/example/windows/.gitignore new file mode 100644 index 000000000..d492d0d98 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/windows/.gitignore @@ -0,0 +1,17 @@ +flutter/ephemeral/ + +# Visual Studio user-specific files. +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual Studio build-related files. +x64/ +x86/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/windows/CMakeLists.txt b/pkgs/jnigen/example/pdfbox_plugin/example/windows/CMakeLists.txt new file mode 100644 index 000000000..c23339761 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/windows/CMakeLists.txt @@ -0,0 +1,101 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(pdfbox_plugin_example LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "pdfbox_plugin_example") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Define build configuration option. +get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(IS_MULTICONFIG) + set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" + CACHE STRING "" FORCE) +else() + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") + endif() +endif() +# Define settings for the Profile build mode. +set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") +set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") +set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") +set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") + +# Use Unicode for all projects. +add_definitions(-DUNICODE -D_UNICODE) + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_17) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# Support files are copied into place next to the executable, so that it can +# run in place. This is done instead of making a separate bundle (as on Linux) +# so that building and running from within Visual Studio will work. +set(BUILD_BUNDLE_DIR "$") +# Make the "install" step default, as it's required to run. +set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + CONFIGURATIONS Profile;Release + COMPONENT Runtime) diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/windows/flutter/CMakeLists.txt b/pkgs/jnigen/example/pdfbox_plugin/example/windows/flutter/CMakeLists.txt new file mode 100644 index 000000000..930d2071a --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/windows/flutter/CMakeLists.txt @@ -0,0 +1,104 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.14) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") + +# === Flutter Library === +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "flutter_export.h" + "flutter_windows.h" + "flutter_messenger.h" + "flutter_plugin_registrar.h" + "flutter_texture_registrar.h" +) +list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") +add_dependencies(flutter flutter_assemble) + +# === Wrapper === +list(APPEND CPP_WRAPPER_SOURCES_CORE + "core_implementations.cc" + "standard_codec.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_PLUGIN + "plugin_registrar.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_APP + "flutter_engine.cc" + "flutter_view_controller.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") + +# Wrapper sources needed for a plugin. +add_library(flutter_wrapper_plugin STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} +) +apply_standard_settings(flutter_wrapper_plugin) +set_target_properties(flutter_wrapper_plugin PROPERTIES + POSITION_INDEPENDENT_CODE ON) +set_target_properties(flutter_wrapper_plugin PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) +target_include_directories(flutter_wrapper_plugin PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_plugin flutter_assemble) + +# Wrapper sources needed for the runner. +add_library(flutter_wrapper_app STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_APP} +) +apply_standard_settings(flutter_wrapper_app) +target_link_libraries(flutter_wrapper_app PUBLIC flutter) +target_include_directories(flutter_wrapper_app PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_app flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") +set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} + ${PHONY_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" + windows-x64 $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/windows/flutter/generated_plugin_registrant.cc b/pkgs/jnigen/example/pdfbox_plugin/example/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 000000000..8b6d4680a --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void RegisterPlugins(flutter::PluginRegistry* registry) { +} diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/windows/flutter/generated_plugin_registrant.h b/pkgs/jnigen/example/pdfbox_plugin/example/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 000000000..dc139d85a --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/windows/flutter/generated_plugins.cmake b/pkgs/jnigen/example/pdfbox_plugin/example/windows/flutter/generated_plugins.cmake new file mode 100644 index 000000000..facaded73 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/windows/flutter/generated_plugins.cmake @@ -0,0 +1,25 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST + jni + pdfbox_plugin +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/windows/runner/CMakeLists.txt b/pkgs/jnigen/example/pdfbox_plugin/example/windows/runner/CMakeLists.txt new file mode 100644 index 000000000..b9e550fba --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/windows/runner/CMakeLists.txt @@ -0,0 +1,32 @@ +cmake_minimum_required(VERSION 3.14) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} WIN32 + "flutter_window.cpp" + "main.cpp" + "utils.cpp" + "win32_window.cpp" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" + "Runner.rc" + "runner.exe.manifest" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Disable Windows macros that collide with C++ standard library functions. +target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") + +# Add dependency libraries and include directories. Add any application-specific +# dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/windows/runner/Runner.rc b/pkgs/jnigen/example/pdfbox_plugin/example/windows/runner/Runner.rc new file mode 100644 index 000000000..05d079f5f --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/windows/runner/Runner.rc @@ -0,0 +1,121 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APP_ICON ICON "resources\\app_icon.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#ifdef FLUTTER_BUILD_NUMBER +#define VERSION_AS_NUMBER FLUTTER_BUILD_NUMBER +#else +#define VERSION_AS_NUMBER 1,0,0 +#endif + +#ifdef FLUTTER_BUILD_NAME +#define VERSION_AS_STRING #FLUTTER_BUILD_NAME +#else +#define VERSION_AS_STRING "1.0.0" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VERSION_AS_NUMBER + PRODUCTVERSION VERSION_AS_NUMBER + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "com.example" "\0" + VALUE "FileDescription", "pdfbox_plugin_example" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "pdfbox_plugin_example" "\0" + VALUE "LegalCopyright", "Copyright (C) 2022 com.example. All rights reserved." "\0" + VALUE "OriginalFilename", "pdfbox_plugin_example.exe" "\0" + VALUE "ProductName", "pdfbox_plugin_example" "\0" + VALUE "ProductVersion", VERSION_AS_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/windows/runner/flutter_window.cpp b/pkgs/jnigen/example/pdfbox_plugin/example/windows/runner/flutter_window.cpp new file mode 100644 index 000000000..b43b9095e --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/windows/runner/flutter_window.cpp @@ -0,0 +1,61 @@ +#include "flutter_window.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +FlutterWindow::FlutterWindow(const flutter::DartProject& project) + : project_(project) {} + +FlutterWindow::~FlutterWindow() {} + +bool FlutterWindow::OnCreate() { + if (!Win32Window::OnCreate()) { + return false; + } + + RECT frame = GetClientArea(); + + // The size here must match the window dimensions to avoid unnecessary surface + // creation / destruction in the startup path. + flutter_controller_ = std::make_unique( + frame.right - frame.left, frame.bottom - frame.top, project_); + // Ensure that basic setup of the controller was successful. + if (!flutter_controller_->engine() || !flutter_controller_->view()) { + return false; + } + RegisterPlugins(flutter_controller_->engine()); + SetChildContent(flutter_controller_->view()->GetNativeWindow()); + return true; +} + +void FlutterWindow::OnDestroy() { + if (flutter_controller_) { + flutter_controller_ = nullptr; + } + + Win32Window::OnDestroy(); +} + +LRESULT +FlutterWindow::MessageHandler(HWND hwnd, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + // Give Flutter, including plugins, an opportunity to handle window messages. + if (flutter_controller_) { + std::optional result = + flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, + lparam); + if (result) { + return *result; + } + } + + switch (message) { + case WM_FONTCHANGE: + flutter_controller_->engine()->ReloadSystemFonts(); + break; + } + + return Win32Window::MessageHandler(hwnd, message, wparam, lparam); +} diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/windows/runner/flutter_window.h b/pkgs/jnigen/example/pdfbox_plugin/example/windows/runner/flutter_window.h new file mode 100644 index 000000000..6da0652f0 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#include "win32_window.h" + +// A window that does nothing but host a Flutter view. +class FlutterWindow : public Win32Window { + public: + // Creates a new FlutterWindow hosting a Flutter view running |project|. + explicit FlutterWindow(const flutter::DartProject& project); + virtual ~FlutterWindow(); + + protected: + // Win32Window: + bool OnCreate() override; + void OnDestroy() override; + LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, + LPARAM const lparam) noexcept override; + + private: + // The project to run. + flutter::DartProject project_; + + // The Flutter instance hosted by this window. + std::unique_ptr flutter_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/windows/runner/main.cpp b/pkgs/jnigen/example/pdfbox_plugin/example/windows/runner/main.cpp new file mode 100644 index 000000000..44bdbc6f5 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/windows/runner/main.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#include "flutter_window.h" +#include "utils.h" + +int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, + _In_ wchar_t *command_line, _In_ int show_command) { + // Attach to console when present (e.g., 'flutter run') or create a + // new console when running with a debugger. + if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { + CreateAndAttachConsole(); + } + + // Initialize COM, so that it is available for use in the library and/or + // plugins. + ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + + flutter::DartProject project(L"data"); + + std::vector command_line_arguments = + GetCommandLineArguments(); + + project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); + + FlutterWindow window(project); + Win32Window::Point origin(10, 10); + Win32Window::Size size(1280, 720); + if (!window.CreateAndShow(L"pdfbox_plugin_example", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/windows/runner/resource.h b/pkgs/jnigen/example/pdfbox_plugin/example/windows/runner/resource.h new file mode 100644 index 000000000..66a65d1e4 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/windows/runner/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Runner.rc +// +#define IDI_APP_ICON 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/windows/runner/resources/app_icon.ico b/pkgs/jnigen/example/pdfbox_plugin/example/windows/runner/resources/app_icon.ico new file mode 100644 index 000000000..c04e20caf Binary files /dev/null and b/pkgs/jnigen/example/pdfbox_plugin/example/windows/runner/resources/app_icon.ico differ diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/windows/runner/runner.exe.manifest b/pkgs/jnigen/example/pdfbox_plugin/example/windows/runner/runner.exe.manifest new file mode 100644 index 000000000..c977c4a42 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/windows/runner/runner.exe.manifest @@ -0,0 +1,20 @@ + + + + + PerMonitorV2 + + + + + + + + + + + + + + + diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/windows/runner/utils.cpp b/pkgs/jnigen/example/pdfbox_plugin/example/windows/runner/utils.cpp new file mode 100644 index 000000000..f5bf9fa0f --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/windows/runner/utils.cpp @@ -0,0 +1,64 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +void CreateAndAttachConsole() { + if (::AllocConsole()) { + FILE *unused; + if (freopen_s(&unused, "CONOUT$", "w", stdout)) { + _dup2(_fileno(stdout), 1); + } + if (freopen_s(&unused, "CONOUT$", "w", stderr)) { + _dup2(_fileno(stdout), 2); + } + std::ios::sync_with_stdio(); + FlutterDesktopResyncOutputStreams(); + } +} + +std::vector GetCommandLineArguments() { + // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. + int argc; + wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + if (argv == nullptr) { + return std::vector(); + } + + std::vector command_line_arguments; + + // Skip the first argument as it's the binary name. + for (int i = 1; i < argc; i++) { + command_line_arguments.push_back(Utf8FromUtf16(argv[i])); + } + + ::LocalFree(argv); + + return command_line_arguments; +} + +std::string Utf8FromUtf16(const wchar_t* utf16_string) { + if (utf16_string == nullptr) { + return std::string(); + } + int target_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, nullptr, 0, nullptr, nullptr); + std::string utf8_string; + if (target_length == 0 || target_length > utf8_string.max_size()) { + return utf8_string; + } + utf8_string.resize(target_length); + int converted_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, utf8_string.data(), + target_length, nullptr, nullptr); + if (converted_length == 0) { + return std::string(); + } + return utf8_string; +} diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/windows/runner/utils.h b/pkgs/jnigen/example/pdfbox_plugin/example/windows/runner/utils.h new file mode 100644 index 000000000..3879d5475 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// Creates a console for the process, and redirects stdout and stderr to +// it for both the runner and the Flutter library. +void CreateAndAttachConsole(); + +// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string +// encoded in UTF-8. Returns an empty std::string on failure. +std::string Utf8FromUtf16(const wchar_t* utf16_string); + +// Gets the command line arguments passed in as a std::vector, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/windows/runner/win32_window.cpp b/pkgs/jnigen/example/pdfbox_plugin/example/windows/runner/win32_window.cpp new file mode 100644 index 000000000..c10f08dc7 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/windows/runner/win32_window.cpp @@ -0,0 +1,245 @@ +#include "win32_window.h" + +#include + +#include "resource.h" + +namespace { + +constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; + +// The number of Win32Window objects that currently exist. +static int g_active_window_count = 0; + +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); + +// Scale helper to convert logical scaler values to physical using passed in +// scale factor +int Scale(int source, double scale_factor) { + return static_cast(source * scale_factor); +} + +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. +// This API is only needed for PerMonitor V1 awareness mode. +void EnableFullDpiSupportIfAvailable(HWND hwnd) { + HMODULE user32_module = LoadLibraryA("User32.dll"); + if (!user32_module) { + return; + } + auto enable_non_client_dpi_scaling = + reinterpret_cast( + GetProcAddress(user32_module, "EnableNonClientDpiScaling")); + if (enable_non_client_dpi_scaling != nullptr) { + enable_non_client_dpi_scaling(hwnd); + FreeLibrary(user32_module); + } +} + +} // namespace + +// Manages the Win32Window's window class registration. +class WindowClassRegistrar { + public: + ~WindowClassRegistrar() = default; + + // Returns the singleton registar instance. + static WindowClassRegistrar* GetInstance() { + if (!instance_) { + instance_ = new WindowClassRegistrar(); + } + return instance_; + } + + // Returns the name of the window class, registering the class if it hasn't + // previously been registered. + const wchar_t* GetWindowClass(); + + // Unregisters the window class. Should only be called if there are no + // instances of the window. + void UnregisterWindowClass(); + + private: + WindowClassRegistrar() = default; + + static WindowClassRegistrar* instance_; + + bool class_registered_ = false; +}; + +WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; + +const wchar_t* WindowClassRegistrar::GetWindowClass() { + if (!class_registered_) { + WNDCLASS window_class{}; + window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); + window_class.lpszClassName = kWindowClassName; + window_class.style = CS_HREDRAW | CS_VREDRAW; + window_class.cbClsExtra = 0; + window_class.cbWndExtra = 0; + window_class.hInstance = GetModuleHandle(nullptr); + window_class.hIcon = + LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); + window_class.hbrBackground = 0; + window_class.lpszMenuName = nullptr; + window_class.lpfnWndProc = Win32Window::WndProc; + RegisterClass(&window_class); + class_registered_ = true; + } + return kWindowClassName; +} + +void WindowClassRegistrar::UnregisterWindowClass() { + UnregisterClass(kWindowClassName, nullptr); + class_registered_ = false; +} + +Win32Window::Win32Window() { + ++g_active_window_count; +} + +Win32Window::~Win32Window() { + --g_active_window_count; + Destroy(); +} + +bool Win32Window::CreateAndShow(const std::wstring& title, + const Point& origin, + const Size& size) { + Destroy(); + + const wchar_t* window_class = + WindowClassRegistrar::GetInstance()->GetWindowClass(); + + const POINT target_point = {static_cast(origin.x), + static_cast(origin.y)}; + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / 96.0; + + HWND window = CreateWindow( + window_class, title.c_str(), WS_OVERLAPPEDWINDOW | WS_VISIBLE, + Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), + Scale(size.width, scale_factor), Scale(size.height, scale_factor), + nullptr, nullptr, GetModuleHandle(nullptr), this); + + if (!window) { + return false; + } + + return OnCreate(); +} + +// static +LRESULT CALLBACK Win32Window::WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + if (message == WM_NCCREATE) { + auto window_struct = reinterpret_cast(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(window_struct->lpCreateParams); + EnableFullDpiSupportIfAvailable(window); + that->window_handle_ = window; + } else if (Win32Window* that = GetThisFromHandle(window)) { + return that->MessageHandler(window, message, wparam, lparam); + } + + return DefWindowProc(window, message, wparam, lparam); +} + +LRESULT +Win32Window::MessageHandler(HWND hwnd, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + switch (message) { + case WM_DESTROY: + window_handle_ = nullptr; + Destroy(); + if (quit_on_close_) { + PostQuitMessage(0); + } + return 0; + + case WM_DPICHANGED: { + auto newRectSize = reinterpret_cast(lparam); + LONG newWidth = newRectSize->right - newRectSize->left; + LONG newHeight = newRectSize->bottom - newRectSize->top; + + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, + newHeight, SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } + case WM_SIZE: { + RECT rect = GetClientArea(); + if (child_content_ != nullptr) { + // Size and position the child window. + MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, TRUE); + } + return 0; + } + + case WM_ACTIVATE: + if (child_content_ != nullptr) { + SetFocus(child_content_); + } + return 0; + } + + return DefWindowProc(window_handle_, message, wparam, lparam); +} + +void Win32Window::Destroy() { + OnDestroy(); + + if (window_handle_) { + DestroyWindow(window_handle_); + window_handle_ = nullptr; + } + if (g_active_window_count == 0) { + WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); + } +} + +Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { + return reinterpret_cast( + GetWindowLongPtr(window, GWLP_USERDATA)); +} + +void Win32Window::SetChildContent(HWND content) { + child_content_ = content; + SetParent(content, window_handle_); + RECT frame = GetClientArea(); + + MoveWindow(content, frame.left, frame.top, frame.right - frame.left, + frame.bottom - frame.top, true); + + SetFocus(child_content_); +} + +RECT Win32Window::GetClientArea() { + RECT frame; + GetClientRect(window_handle_, &frame); + return frame; +} + +HWND Win32Window::GetHandle() { + return window_handle_; +} + +void Win32Window::SetQuitOnClose(bool quit_on_close) { + quit_on_close_ = quit_on_close; +} + +bool Win32Window::OnCreate() { + // No-op; provided for subclasses. + return true; +} + +void Win32Window::OnDestroy() { + // No-op; provided for subclasses. +} diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/windows/runner/win32_window.h b/pkgs/jnigen/example/pdfbox_plugin/example/windows/runner/win32_window.h new file mode 100644 index 000000000..17ba43112 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/example/windows/runner/win32_window.h @@ -0,0 +1,98 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// A class abstraction for a high DPI-aware Win32 Window. Intended to be +// inherited from by classes that wish to specialize with custom +// rendering and input handling +class Win32Window { + public: + struct Point { + unsigned int x; + unsigned int y; + Point(unsigned int x, unsigned int y) : x(x), y(y) {} + }; + + struct Size { + unsigned int width; + unsigned int height; + Size(unsigned int width, unsigned int height) + : width(width), height(height) {} + }; + + Win32Window(); + virtual ~Win32Window(); + + // Creates and shows a win32 window with |title| and position and size using + // |origin| and |size|. New windows are created on the default monitor. Window + // sizes are specified to the OS in physical pixels, hence to ensure a + // consistent size to will treat the width height passed in to this function + // as logical pixels and scale to appropriate for the default monitor. Returns + // true if the window was created successfully. + bool CreateAndShow(const std::wstring& title, + const Point& origin, + const Size& size); + + // Release OS resources associated with window. + void Destroy(); + + // Inserts |content| into the window tree. + void SetChildContent(HWND content); + + // Returns the backing Window handle to enable clients to set icon and other + // window properties. Returns nullptr if the window has been destroyed. + HWND GetHandle(); + + // If true, closing this window will quit the application. + void SetQuitOnClose(bool quit_on_close); + + // Return a RECT representing the bounds of the current client area. + RECT GetClientArea(); + + protected: + // Processes and route salient window messages for mouse handling, + // size change and DPI. Delegates handling of these to member overloads that + // inheriting classes can handle. + virtual LRESULT MessageHandler(HWND window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Called when CreateAndShow is called, allowing subclass window-related + // setup. Subclasses should return false if setup fails. + virtual bool OnCreate(); + + // Called when Destroy is called. + virtual void OnDestroy(); + + private: + friend class WindowClassRegistrar; + + // OS callback called by message pump. Handles the WM_NCCREATE message which + // is passed when the non-client area is being created and enables automatic + // non-client DPI scaling so that the non-client area automatically + // responsponds to changes in DPI. All other messages are handled by + // MessageHandler. + static LRESULT CALLBACK WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Retrieves a class instance pointer for |window| + static Win32Window* GetThisFromHandle(HWND const window) noexcept; + + bool quit_on_close_ = false; + + // window handle for top level window. + HWND window_handle_ = nullptr; + + // window handle for hosted content. + HWND child_content_ = nullptr; +}; + +#endif // RUNNER_WIN32_WINDOW_H_ diff --git a/pkgs/jnigen/example/pdfbox_plugin/jnigen.yaml b/pkgs/jnigen/example/pdfbox_plugin/jnigen.yaml new file mode 100644 index 000000000..584a3bf7e --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/jnigen.yaml @@ -0,0 +1,80 @@ +## String to be pasted verbatim into generated bindings +preamble: | + // Generated from Apache PDFBox library which is licensed under the Apache License 2.0. + // The following copyright from the original authors applies. + // + // Licensed to the Apache Software Foundation (ASF) under one or more + // contributor license agreements. See the NOTICE file distributed with + // this work for additional information regarding copyright ownership. + // The ASF licenses this file to You under the Apache License, Version 2.0 + // (the "License"); you may not use this file except in compliance with + // the License. You may obtain a copy of the License at + // + // http://www.apache.org/licenses/LICENSE-2.0 + // + // Unless required by applicable law or agreed to in writing, software + // distributed under the License is distributed on an "AS IS" BASIS, + // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + // See the License for the specific language governing permissions and + // limitations under the License. + +## Output configuration +output: + c: + ## Path to write generated C bindings + path: 'src/' + ## C files can be stored in a different sub-directory inside root. + ## + ## We have a guideline to keep all generated code in third_party/ since the + ## original project's license applies to generated code. So we specify + ## third_party/ as c_subdir while keeping generated CMakeLists.txt in src/. + subdir: 'third_party/' + ## Name of the generated library. This is a required parameter, and used + ## for the name of the shared library and CMake configuration. + library_name: 'pdfbox_plugin' + dart: + ## Generated dart bindings will be written to this path. They will follow + ## the same folder hierarchy as the original Java code. + path: 'lib/src/third_party/' + +## Classes / packages for which bindings need to be generated. +classes: + - 'org.apache.pdfbox.pdmodel.PDDocument' + - 'org.apache.pdfbox.pdmodel.PDDocumentInformation' + - 'org.apache.pdfbox.text.PDFTextStripper' + +## Exclude a problematic static field. Static fields are usually converted +## directly to dart static fields. In the current implementation some string +## escaping problems may occur. +## +## See issue #31 (https://github.com/dart-lang/jnigen/issues/31) for details. +## (This field does not appear in bindings unless full package bindings are +## generated using a `-Dclasses` override.) +## +## TODO(#31): For string fields, it may be better to generate a field getter +## than a direct literal. +exclude: + fields: + - 'org.apache.pdfbox.contentstream.operator.OperatorName#SHOW_TEXT_LINE_AND_SPACE' + +## Dependencies to be downloaded using Maven (Invokes `mvn` command). These +## dependencies are always downloaded along with their transitive dependencies. +## +## Dependencies should be specified using groupID:artifactID:version format +## The downloaded dependencies are automatically added to classpath of the +## Java API scanning process. There's no need to specify these again in +## sourcepath and classpath. +## +## Note that when maven based tooling is used, the first run often has to fetch +## all the dependencies and might take some time. However, maven caches the +## artifacts in local repository, thus subsequent runs will be faster. +maven_downloads: + ## For these dependencies, both source and JARs are downloaded. + source_deps: + - 'org.apache.pdfbox:pdfbox:2.0.26' + ## Runtime dependencies for which bindings aren't generated directly. + ## Only JARs are downloaded. + jar_only_deps: + - 'org.bouncycastle:bcmail-jdk15on:1.70' + - 'org.bouncycastle:bcprov-jdk15on:1.70' + diff --git a/pkgs/jnigen/example/pdfbox_plugin/lib/pdfbox_plugin.dart b/pkgs/jnigen/example/pdfbox_plugin/lib/pdfbox_plugin.dart new file mode 100644 index 000000000..3cdeeff7d --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/lib/pdfbox_plugin.dart @@ -0,0 +1,6 @@ +/// File merely exporting the generated bindings from lib/src/third_party +library pdfbox_plugin; + +export 'src/third_party/org/apache/pdfbox/pdmodel/PDDocument.dart'; +export 'src/third_party/org/apache/pdfbox/pdmodel/PDDocumentInformation.dart'; +export 'src/third_party/org/apache/pdfbox/text/PDFTextStripper.dart'; diff --git a/pkgs/jnigen/example/pdfbox_plugin/lib/src/third_party/_init.dart b/pkgs/jnigen/example/pdfbox_plugin/lib/src/third_party/_init.dart new file mode 100644 index 000000000..57aea60db --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/lib/src/third_party/_init.dart @@ -0,0 +1,25 @@ +// Generated from Apache PDFBox library which is licensed under the Apache License 2.0. +// The following copyright from the original authors applies. +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import "dart:ffi" as ffi; +import "package:jni/internal_helpers_for_jnigen.dart"; + +// Auto-generated initialization code. + +final ffi.Pointer Function(String sym) jniLookup = + ProtectedJniExtensions.initGeneratedLibrary("pdfbox_plugin"); diff --git a/pkgs/jnigen/example/pdfbox_plugin/lib/src/third_party/org/apache/pdfbox/pdmodel/PDDocument.dart b/pkgs/jnigen/example/pdfbox_plugin/lib/src/third_party/org/apache/pdfbox/pdmodel/PDDocument.dart new file mode 100644 index 000000000..b2c40a284 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/lib/src/third_party/org/apache/pdfbox/pdmodel/PDDocument.dart @@ -0,0 +1,1535 @@ +// Generated from Apache PDFBox library which is licensed under the Apache License 2.0. +// The following copyright from the original authors applies. +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Autogenerated by jnigen. DO NOT EDIT! + +// ignore_for_file: annotate_overrides +// ignore_for_file: camel_case_extensions +// ignore_for_file: camel_case_types +// ignore_for_file: constant_identifier_names +// ignore_for_file: file_names +// ignore_for_file: lines_longer_than_80_chars +// ignore_for_file: no_leading_underscores_for_local_identifiers +// ignore_for_file: non_constant_identifier_names +// ignore_for_file: overridden_fields +// ignore_for_file: unnecessary_cast +// ignore_for_file: unused_element +// ignore_for_file: unused_field +// ignore_for_file: unused_import +// ignore_for_file: unused_local_variable +// ignore_for_file: unused_shown_name + +import "dart:isolate" show ReceivePort; +import "dart:ffi" as ffi; +import "package:jni/internal_helpers_for_jnigen.dart"; +import "package:jni/jni.dart" as jni; + +import "PDDocumentInformation.dart" as pddocumentinformation_; +import "../../../../_init.dart"; + +/// from: org.apache.pdfbox.pdmodel.PDDocument +/// +/// This is the in-memory representation of the PDF document. +/// The \#close() method must be called once the document is no longer needed. +///@author Ben Litchfield +class PDDocument extends jni.JObject { + @override + late final jni.JObjType $type = type; + + PDDocument.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $PDDocumentType(); + static final _new0 = jniLookup>( + "PDDocument__new0") + .asFunction(); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + /// + /// Creates an empty PDF document. + /// You need to add at least one page for the document to be valid. + factory PDDocument() { + return PDDocument.fromRef(_new0().object); + } + + static final _new1 = jniLookup< + ffi + .NativeFunction)>>( + "PDDocument__new1") + .asFunction)>(); + + /// from: public void (org.apache.pdfbox.io.MemoryUsageSetting memUsageSetting) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Creates an empty PDF document. + /// You need to add at least one page for the document to be valid. + ///@param memUsageSetting defines how memory is used for buffering PDF streams + factory PDDocument.new1( + jni.JObject memUsageSetting, + ) { + return PDDocument.fromRef(_new1(memUsageSetting.reference).object); + } + + static final _new2 = jniLookup< + ffi + .NativeFunction)>>( + "PDDocument__new2") + .asFunction)>(); + + /// from: public void (org.apache.pdfbox.cos.COSDocument doc) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Constructor that uses an existing document. The COSDocument that is passed in must be valid. + ///@param doc The COSDocument that this document wraps. + factory PDDocument.new2( + jni.JObject doc, + ) { + return PDDocument.fromRef(_new2(doc.reference).object); + } + + static final _new3 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDDocument__new3") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void (org.apache.pdfbox.cos.COSDocument doc, org.apache.pdfbox.io.RandomAccessRead source) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Constructor that uses an existing document. The COSDocument that is passed in must be valid. + ///@param doc The COSDocument that this document wraps. + ///@param source the parser which is used to read the pdf + factory PDDocument.new3( + jni.JObject doc, + jni.JObject source, + ) { + return PDDocument.fromRef(_new3(doc.reference, source.reference).object); + } + + static final _new4 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>("PDDocument__new4") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); + + /// from: public void (org.apache.pdfbox.cos.COSDocument doc, org.apache.pdfbox.io.RandomAccessRead source, org.apache.pdfbox.pdmodel.encryption.AccessPermission permission) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Constructor that uses an existing document. The COSDocument that is passed in must be valid. + ///@param doc The COSDocument that this document wraps. + ///@param source the parser which is used to read the pdf + ///@param permission he access permissions of the pdf + factory PDDocument.new4( + jni.JObject doc, + jni.JObject source, + jni.JObject permission, + ) { + return PDDocument.fromRef( + _new4(doc.reference, source.reference, permission.reference).object); + } + + static final _addPage = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDDocument__addPage") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void addPage(org.apache.pdfbox.pdmodel.PDPage page) + /// + /// This will add a page to the document. This is a convenience method, that will add the page to the root of the + /// hierarchy and set the parent of the page to the root. + ///@param page The page to add to the document. + void addPage( + jni.JObject page, + ) { + return _addPage(reference, page.reference).check(); + } + + static final _addSignature = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDDocument__addSignature") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void addSignature(org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature sigObject) + /// + /// Add parameters of signature to be created externally using default signature options. See + /// \#saveIncrementalForExternalSigning(OutputStream) method description on external + /// signature creation scenario details. + /// + /// Only one signature may be added in a document. To sign several times, + /// load document, add signature, save incremental and close again. + ///@param sigObject is the PDSignatureField model + ///@throws IOException if there is an error creating required fields + ///@throws IllegalStateException if one attempts to add several signature + /// fields. + void addSignature( + jni.JObject sigObject, + ) { + return _addSignature(reference, sigObject.reference).check(); + } + + static final _addSignature1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>("PDDocument__addSignature1") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); + + /// from: public void addSignature(org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature sigObject, org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureOptions options) + /// + /// Add parameters of signature to be created externally. See + /// \#saveIncrementalForExternalSigning(OutputStream) method description on external + /// signature creation scenario details. + /// + /// Only one signature may be added in a document. To sign several times, + /// load document, add signature, save incremental and close again. + ///@param sigObject is the PDSignatureField model + ///@param options signature options + ///@throws IOException if there is an error creating required fields + ///@throws IllegalStateException if one attempts to add several signature + /// fields. + void addSignature1( + jni.JObject sigObject, + jni.JObject options, + ) { + return _addSignature1(reference, sigObject.reference, options.reference) + .check(); + } + + static final _addSignature2 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>("PDDocument__addSignature2") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); + + /// from: public void addSignature(org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature sigObject, org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureInterface signatureInterface) + /// + /// Add a signature to be created using the instance of given interface. + /// + /// Only one signature may be added in a document. To sign several times, + /// load document, add signature, save incremental and close again. + ///@param sigObject is the PDSignatureField model + ///@param signatureInterface is an interface whose implementation provides + /// signing capabilities. Can be null if external signing if used. + ///@throws IOException if there is an error creating required fields + ///@throws IllegalStateException if one attempts to add several signature + /// fields. + void addSignature2( + jni.JObject sigObject, + jni.JObject signatureInterface, + ) { + return _addSignature2( + reference, sigObject.reference, signatureInterface.reference) + .check(); + } + + static final _addSignature3 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>("PDDocument__addSignature3") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void addSignature(org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature sigObject, org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureInterface signatureInterface, org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureOptions options) + /// + /// This will add a signature to the document. If the 0-based page number in the options + /// parameter is smaller than 0 or larger than max, the nearest valid page number will be used + /// (i.e. 0 or max) and no exception will be thrown. + /// + /// Only one signature may be added in a document. To sign several times, + /// load document, add signature, save incremental and close again. + ///@param sigObject is the PDSignatureField model + ///@param signatureInterface is an interface whose implementation provides + /// signing capabilities. Can be null if external signing if used. + ///@param options signature options + ///@throws IOException if there is an error creating required fields + ///@throws IllegalStateException if one attempts to add several signature + /// fields. + void addSignature3( + jni.JObject sigObject, + jni.JObject signatureInterface, + jni.JObject options, + ) { + return _addSignature3(reference, sigObject.reference, + signatureInterface.reference, options.reference) + .check(); + } + + static final _addSignatureField = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>("PDDocument__addSignatureField") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void addSignatureField(java.util.List sigFields, org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureInterface signatureInterface, org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureOptions options) + /// + /// This will add a list of signature fields to the document. + ///@param sigFields are the PDSignatureFields that should be added to the document + ///@param signatureInterface is an interface whose implementation provides + /// signing capabilities. Can be null if external signing if used. + ///@param options signature options + ///@throws IOException if there is an error creating required fields + ///@deprecated The method is misleading, because only one signature may be + /// added in a document. The method will be removed in the future. + void addSignatureField( + jni.JList sigFields, + jni.JObject signatureInterface, + jni.JObject options, + ) { + return _addSignatureField(reference, sigFields.reference, + signatureInterface.reference, options.reference) + .check(); + } + + static final _removePage = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDDocument__removePage") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void removePage(org.apache.pdfbox.pdmodel.PDPage page) + /// + /// Remove the page from the document. + ///@param page The page to remove from the document. + void removePage( + jni.JObject page, + ) { + return _removePage(reference, page.reference).check(); + } + + static final _removePage1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Int32)>>("PDDocument__removePage1") + .asFunction, int)>(); + + /// from: public void removePage(int pageNumber) + /// + /// Remove the page from the document. + ///@param pageNumber 0 based index to page number. + void removePage1( + int pageNumber, + ) { + return _removePage1(reference, pageNumber).check(); + } + + static final _importPage = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDDocument__importPage") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public org.apache.pdfbox.pdmodel.PDPage importPage(org.apache.pdfbox.pdmodel.PDPage page) + /// The returned object must be released after use, by calling the [release] method. + /// + /// This will import and copy the contents from another location. Currently the content stream is + /// stored in a scratch file. The scratch file is associated with the document. If you are adding + /// a page to this document from another document and want to copy the contents to this + /// document's scratch file then use this method otherwise just use the \#addPage addPage() + /// method. + /// + /// Unlike \#addPage addPage(), this method creates a new PDPage object. If your page has + /// annotations, and if these link to pages not in the target document, then the target document + /// might become huge. What you need to do is to delete page references of such annotations. See + ///
here for how to do this. + /// + /// Inherited (global) resources are ignored because these can contain resources not needed for + /// this page which could bloat your document, see + /// PDFBOX-28 and related issues. + /// If you need them, call importedPage.setResources(page.getResources()); + /// + /// This method should only be used to import a page from a loaded document, not from a generated + /// document because these can contain unfinished parts, e.g. font subsetting information. + ///@param page The page to import. + ///@return The page that was imported. + ///@throws IOException If there is an error copying the page. + jni.JObject importPage( + jni.JObject page, + ) { + return const jni.JObjectType() + .fromRef(_importPage(reference, page.reference).object); + } + + static final _getDocument = jniLookup< + ffi + .NativeFunction)>>( + "PDDocument__getDocument") + .asFunction)>(); + + /// from: public org.apache.pdfbox.cos.COSDocument getDocument() + /// The returned object must be released after use, by calling the [release] method. + /// + /// This will get the low level document. + ///@return The document that this layer sits on top of. + jni.JObject getDocument() { + return const jni.JObjectType().fromRef(_getDocument(reference).object); + } + + static final _getDocumentInformation = jniLookup< + ffi + .NativeFunction)>>( + "PDDocument__getDocumentInformation") + .asFunction)>(); + + /// from: public org.apache.pdfbox.pdmodel.PDDocumentInformation getDocumentInformation() + /// The returned object must be released after use, by calling the [release] method. + /// + /// This will get the document info dictionary. If it doesn't exist, an empty document info + /// dictionary is created in the document trailer. + /// + /// In PDF 2.0 this is deprecated except for two entries, /CreationDate and /ModDate. For any other + /// document level metadata, a metadata stream should be used instead, see + /// PDDocumentCatalog\#getMetadata(). + ///@return The documents /Info dictionary, never null. + pddocumentinformation_.PDDocumentInformation getDocumentInformation() { + return const pddocumentinformation_.$PDDocumentInformationType() + .fromRef(_getDocumentInformation(reference).object); + } + + static final _setDocumentInformation = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDDocument__setDocumentInformation") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void setDocumentInformation(org.apache.pdfbox.pdmodel.PDDocumentInformation info) + /// + /// This will set the document information for this document. + /// + /// In PDF 2.0 this is deprecated except for two entries, /CreationDate and /ModDate. For any other + /// document level metadata, a metadata stream should be used instead, see + /// PDDocumentCatalog\#setMetadata(org.apache.pdfbox.pdmodel.common.PDMetadata) PDDocumentCatalog\#setMetadata(PDMetadata). + ///@param info The updated document information. + void setDocumentInformation( + pddocumentinformation_.PDDocumentInformation info, + ) { + return _setDocumentInformation(reference, info.reference).check(); + } + + static final _getDocumentCatalog = jniLookup< + ffi + .NativeFunction)>>( + "PDDocument__getDocumentCatalog") + .asFunction)>(); + + /// from: public org.apache.pdfbox.pdmodel.PDDocumentCatalog getDocumentCatalog() + /// The returned object must be released after use, by calling the [release] method. + /// + /// This will get the document CATALOG. This is guaranteed to not return null. + ///@return The documents /Root dictionary + jni.JObject getDocumentCatalog() { + return const jni.JObjectType() + .fromRef(_getDocumentCatalog(reference).object); + } + + static final _isEncrypted = jniLookup< + ffi + .NativeFunction)>>( + "PDDocument__isEncrypted") + .asFunction)>(); + + /// from: public boolean isEncrypted() + /// + /// This will tell if this document is encrypted or not. + ///@return true If this document is encrypted. + bool isEncrypted() { + return _isEncrypted(reference).boolean; + } + + static final _getEncryption = jniLookup< + ffi + .NativeFunction)>>( + "PDDocument__getEncryption") + .asFunction)>(); + + /// from: public org.apache.pdfbox.pdmodel.encryption.PDEncryption getEncryption() + /// The returned object must be released after use, by calling the [release] method. + /// + /// This will get the encryption dictionary for this document. This will still return the parameters if the document + /// was decrypted. As the encryption architecture in PDF documents is pluggable this returns an abstract class, + /// but the only supported subclass at this time is a + /// PDStandardEncryption object. + ///@return The encryption dictionary(most likely a PDStandardEncryption object) + jni.JObject getEncryption() { + return const jni.JObjectType().fromRef(_getEncryption(reference).object); + } + + static final _setEncryptionDictionary = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>>( + "PDDocument__setEncryptionDictionary") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void setEncryptionDictionary(org.apache.pdfbox.pdmodel.encryption.PDEncryption encryption) + /// + /// This will set the encryption dictionary for this document. + ///@param encryption The encryption dictionary(most likely a PDStandardEncryption object) + ///@throws IOException If there is an error determining which security handler to use. + void setEncryptionDictionary( + jni.JObject encryption, + ) { + return _setEncryptionDictionary(reference, encryption.reference).check(); + } + + static final _getLastSignatureDictionary = jniLookup< + ffi + .NativeFunction)>>( + "PDDocument__getLastSignatureDictionary") + .asFunction)>(); + + /// from: public org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature getLastSignatureDictionary() + /// The returned object must be released after use, by calling the [release] method. + /// + /// This will return the last signature from the field tree. Note that this may not be the + /// last in time when empty signature fields are created first but signed after other fields. + ///@return the last signature as PDSignatureField. + ///@throws IOException if no document catalog can be found. + jni.JObject getLastSignatureDictionary() { + return const jni.JObjectType() + .fromRef(_getLastSignatureDictionary(reference).object); + } + + static final _getSignatureFields = jniLookup< + ffi + .NativeFunction)>>( + "PDDocument__getSignatureFields") + .asFunction)>(); + + /// from: public java.util.List getSignatureFields() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Retrieve all signature fields from the document. + ///@return a List of PDSignatureFields + ///@throws IOException if no document catalog can be found. + jni.JList getSignatureFields() { + return const jni.JListType(jni.JObjectType()) + .fromRef(_getSignatureFields(reference).object); + } + + static final _getSignatureDictionaries = jniLookup< + ffi + .NativeFunction)>>( + "PDDocument__getSignatureDictionaries") + .asFunction)>(); + + /// from: public java.util.List getSignatureDictionaries() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Retrieve all signature dictionaries from the document. + ///@return a List of PDSignatureFields + ///@throws IOException if no document catalog can be found. + jni.JList getSignatureDictionaries() { + return const jni.JListType(jni.JObjectType()) + .fromRef(_getSignatureDictionaries(reference).object); + } + + static final _registerTrueTypeFontForClosing = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>>( + "PDDocument__registerTrueTypeFontForClosing") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void registerTrueTypeFontForClosing(org.apache.fontbox.ttf.TrueTypeFont ttf) + /// + /// For internal PDFBox use when creating PDF documents: register a TrueTypeFont to make sure it + /// is closed when the PDDocument is closed to avoid memory leaks. Users don't have to call this + /// method, it is done by the appropriate PDFont classes. + ///@param ttf + void registerTrueTypeFontForClosing( + jni.JObject ttf, + ) { + return _registerTrueTypeFontForClosing(reference, ttf.reference).check(); + } + + static final _load = jniLookup< + ffi + .NativeFunction)>>( + "PDDocument__load") + .asFunction)>(); + + /// from: static public org.apache.pdfbox.pdmodel.PDDocument load(java.io.File file) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Parses a PDF. Unrestricted main memory will be used for buffering PDF streams. + ///@param file file to be loaded + ///@return loaded document + ///@throws InvalidPasswordException If the file required a non-empty password. + ///@throws IOException in case of a file reading or parsing error + static PDDocument load( + jni.JObject file, + ) { + return const $PDDocumentType().fromRef(_load(file.reference).object); + } + + static final _load1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDDocument__load1") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: static public org.apache.pdfbox.pdmodel.PDDocument load(java.io.File file, org.apache.pdfbox.io.MemoryUsageSetting memUsageSetting) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Parses a PDF. + ///@param file file to be loaded + ///@param memUsageSetting defines how memory is used for buffering PDF streams + ///@return loaded document + ///@throws InvalidPasswordException If the file required a non-empty password. + ///@throws IOException in case of a file reading or parsing error + static PDDocument load1( + jni.JObject file, + jni.JObject memUsageSetting, + ) { + return const $PDDocumentType() + .fromRef(_load1(file.reference, memUsageSetting.reference).object); + } + + static final _load2 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDDocument__load2") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: static public org.apache.pdfbox.pdmodel.PDDocument load(java.io.File file, java.lang.String password) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Parses a PDF. Unrestricted main memory will be used for buffering PDF streams. + ///@param file file to be loaded + ///@param password password to be used for decryption + ///@return loaded document + ///@throws InvalidPasswordException If the password is incorrect. + ///@throws IOException in case of a file reading or parsing error + static PDDocument load2( + jni.JObject file, + jni.JString password, + ) { + return const $PDDocumentType() + .fromRef(_load2(file.reference, password.reference).object); + } + + static final _load3 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>("PDDocument__load3") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); + + /// from: static public org.apache.pdfbox.pdmodel.PDDocument load(java.io.File file, java.lang.String password, org.apache.pdfbox.io.MemoryUsageSetting memUsageSetting) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Parses a PDF. + ///@param file file to be loaded + ///@param password password to be used for decryption + ///@param memUsageSetting defines how memory is used for buffering PDF streams + ///@return loaded document + ///@throws InvalidPasswordException If the password is incorrect. + ///@throws IOException in case of a file reading or parsing error + static PDDocument load3( + jni.JObject file, + jni.JString password, + jni.JObject memUsageSetting, + ) { + return const $PDDocumentType().fromRef( + _load3(file.reference, password.reference, memUsageSetting.reference) + .object); + } + + static final _load4 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>("PDDocument__load4") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer, ffi.Pointer)>(); + + /// from: static public org.apache.pdfbox.pdmodel.PDDocument load(java.io.File file, java.lang.String password, java.io.InputStream keyStore, java.lang.String alias) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Parses a PDF. Unrestricted main memory will be used for buffering PDF streams. + ///@param file file to be loaded + ///@param password password to be used for decryption + ///@param keyStore key store to be used for decryption when using public key security + ///@param alias alias to be used for decryption when using public key security + ///@return loaded document + ///@throws IOException in case of a file reading or parsing error + static PDDocument load4( + jni.JObject file, + jni.JString password, + jni.JObject keyStore, + jni.JString alias, + ) { + return const $PDDocumentType().fromRef(_load4(file.reference, + password.reference, keyStore.reference, alias.reference) + .object); + } + + static final _load5 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>("PDDocument__load5") + .asFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>(); + + /// from: static public org.apache.pdfbox.pdmodel.PDDocument load(java.io.File file, java.lang.String password, java.io.InputStream keyStore, java.lang.String alias, org.apache.pdfbox.io.MemoryUsageSetting memUsageSetting) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Parses a PDF. + ///@param file file to be loaded + ///@param password password to be used for decryption + ///@param keyStore key store to be used for decryption when using public key security + ///@param alias alias to be used for decryption when using public key security + ///@param memUsageSetting defines how memory is used for buffering PDF streams + ///@return loaded document + ///@throws IOException in case of a file reading or parsing error + static PDDocument load5( + jni.JObject file, + jni.JString password, + jni.JObject keyStore, + jni.JString alias, + jni.JObject memUsageSetting, + ) { + return const $PDDocumentType().fromRef(_load5( + file.reference, + password.reference, + keyStore.reference, + alias.reference, + memUsageSetting.reference) + .object); + } + + static final _load6 = jniLookup< + ffi + .NativeFunction)>>( + "PDDocument__load6") + .asFunction)>(); + + /// from: static public org.apache.pdfbox.pdmodel.PDDocument load(java.io.InputStream input) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Parses a PDF. The given input stream is copied to the memory to enable random access to the + /// pdf. Unrestricted main memory will be used for buffering PDF streams. + ///@param input stream that contains the document. Don't forget to close it after loading. + ///@return loaded document + ///@throws InvalidPasswordException If the PDF required a non-empty password. + ///@throws IOException In case of a reading or parsing error. + static PDDocument load6( + jni.JObject input, + ) { + return const $PDDocumentType().fromRef(_load6(input.reference).object); + } + + static final _load7 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDDocument__load7") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: static public org.apache.pdfbox.pdmodel.PDDocument load(java.io.InputStream input, org.apache.pdfbox.io.MemoryUsageSetting memUsageSetting) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Parses a PDF. Depending on the memory settings parameter the given input stream is either + /// copied to main memory or to a temporary file to enable random access to the pdf. + ///@param input stream that contains the document. Don't forget to close it after loading. + ///@param memUsageSetting defines how memory is used for buffering input stream and PDF streams + ///@return loaded document + ///@throws InvalidPasswordException If the PDF required a non-empty password. + ///@throws IOException In case of a reading or parsing error. + static PDDocument load7( + jni.JObject input, + jni.JObject memUsageSetting, + ) { + return const $PDDocumentType() + .fromRef(_load7(input.reference, memUsageSetting.reference).object); + } + + static final _load8 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDDocument__load8") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: static public org.apache.pdfbox.pdmodel.PDDocument load(java.io.InputStream input, java.lang.String password) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Parses a PDF. The given input stream is copied to the memory to enable random access to the + /// pdf. Unrestricted main memory will be used for buffering PDF streams. + ///@param input stream that contains the document. Don't forget to close it after loading. + ///@param password password to be used for decryption + ///@return loaded document + ///@throws InvalidPasswordException If the password is incorrect. + ///@throws IOException In case of a reading or parsing error. + static PDDocument load8( + jni.JObject input, + jni.JString password, + ) { + return const $PDDocumentType() + .fromRef(_load8(input.reference, password.reference).object); + } + + static final _load9 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>("PDDocument__load9") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer, ffi.Pointer)>(); + + /// from: static public org.apache.pdfbox.pdmodel.PDDocument load(java.io.InputStream input, java.lang.String password, java.io.InputStream keyStore, java.lang.String alias) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Parses a PDF. The given input stream is copied to the memory to enable random access to the + /// pdf. Unrestricted main memory will be used for buffering PDF streams. + ///@param input stream that contains the document. Don't forget to close it after loading. + ///@param password password to be used for decryption + ///@param keyStore key store to be used for decryption when using public key security + ///@param alias alias to be used for decryption when using public key security + ///@return loaded document + ///@throws IOException In case of a reading or parsing error. + static PDDocument load9( + jni.JObject input, + jni.JString password, + jni.JObject keyStore, + jni.JString alias, + ) { + return const $PDDocumentType().fromRef(_load9(input.reference, + password.reference, keyStore.reference, alias.reference) + .object); + } + + static final _load10 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>("PDDocument__load10") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); + + /// from: static public org.apache.pdfbox.pdmodel.PDDocument load(java.io.InputStream input, java.lang.String password, org.apache.pdfbox.io.MemoryUsageSetting memUsageSetting) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Parses a PDF. Depending on the memory settings parameter the given input stream is either + /// copied to main memory or to a temporary file to enable random access to the pdf. + ///@param input stream that contains the document. Don't forget to close it after loading. + ///@param password password to be used for decryption + ///@param memUsageSetting defines how memory is used for buffering input stream and PDF streams + ///@return loaded document + ///@throws InvalidPasswordException If the password is incorrect. + ///@throws IOException In case of a reading or parsing error. + static PDDocument load10( + jni.JObject input, + jni.JString password, + jni.JObject memUsageSetting, + ) { + return const $PDDocumentType().fromRef( + _load10(input.reference, password.reference, memUsageSetting.reference) + .object); + } + + static final _load11 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>("PDDocument__load11") + .asFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>(); + + /// from: static public org.apache.pdfbox.pdmodel.PDDocument load(java.io.InputStream input, java.lang.String password, java.io.InputStream keyStore, java.lang.String alias, org.apache.pdfbox.io.MemoryUsageSetting memUsageSetting) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Parses a PDF. Depending on the memory settings parameter the given input stream is either + /// copied to memory or to a temporary file to enable random access to the pdf. + ///@param input stream that contains the document. Don't forget to close it after loading. + ///@param password password to be used for decryption + ///@param keyStore key store to be used for decryption when using public key security + ///@param alias alias to be used for decryption when using public key security + ///@param memUsageSetting defines how memory is used for buffering input stream and PDF streams + ///@return loaded document + ///@throws InvalidPasswordException If the password is incorrect. + ///@throws IOException In case of a reading or parsing error. + static PDDocument load11( + jni.JObject input, + jni.JString password, + jni.JObject keyStore, + jni.JString alias, + jni.JObject memUsageSetting, + ) { + return const $PDDocumentType().fromRef(_load11( + input.reference, + password.reference, + keyStore.reference, + alias.reference, + memUsageSetting.reference) + .object); + } + + static final _load12 = jniLookup< + ffi + .NativeFunction)>>( + "PDDocument__load12") + .asFunction)>(); + + /// from: static public org.apache.pdfbox.pdmodel.PDDocument load(byte[] input) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Parses a PDF. Unrestricted main memory will be used for buffering PDF streams. + ///@param input byte array that contains the document. + ///@return loaded document + ///@throws InvalidPasswordException If the PDF required a non-empty password. + ///@throws IOException In case of a reading or parsing error. + static PDDocument load12( + jni.JArray input, + ) { + return const $PDDocumentType().fromRef(_load12(input.reference).object); + } + + static final _load13 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDDocument__load13") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: static public org.apache.pdfbox.pdmodel.PDDocument load(byte[] input, java.lang.String password) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Parses a PDF. Unrestricted main memory will be used for buffering PDF streams. + ///@param input byte array that contains the document. + ///@param password password to be used for decryption + ///@return loaded document + ///@throws InvalidPasswordException If the password is incorrect. + ///@throws IOException In case of a reading or parsing error. + static PDDocument load13( + jni.JArray input, + jni.JString password, + ) { + return const $PDDocumentType() + .fromRef(_load13(input.reference, password.reference).object); + } + + static final _load14 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>("PDDocument__load14") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer, ffi.Pointer)>(); + + /// from: static public org.apache.pdfbox.pdmodel.PDDocument load(byte[] input, java.lang.String password, java.io.InputStream keyStore, java.lang.String alias) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Parses a PDF. Unrestricted main memory will be used for buffering PDF streams. + ///@param input byte array that contains the document. + ///@param password password to be used for decryption + ///@param keyStore key store to be used for decryption when using public key security + ///@param alias alias to be used for decryption when using public key security + ///@return loaded document + ///@throws InvalidPasswordException If the password is incorrect. + ///@throws IOException In case of a reading or parsing error. + static PDDocument load14( + jni.JArray input, + jni.JString password, + jni.JObject keyStore, + jni.JString alias, + ) { + return const $PDDocumentType().fromRef(_load14(input.reference, + password.reference, keyStore.reference, alias.reference) + .object); + } + + static final _load15 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>("PDDocument__load15") + .asFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>(); + + /// from: static public org.apache.pdfbox.pdmodel.PDDocument load(byte[] input, java.lang.String password, java.io.InputStream keyStore, java.lang.String alias, org.apache.pdfbox.io.MemoryUsageSetting memUsageSetting) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Parses a PDF. + ///@param input byte array that contains the document. + ///@param password password to be used for decryption + ///@param keyStore key store to be used for decryption when using public key security + ///@param alias alias to be used for decryption when using public key security + ///@param memUsageSetting defines how memory is used for buffering input stream and PDF streams + ///@return loaded document + ///@throws InvalidPasswordException If the password is incorrect. + ///@throws IOException In case of a reading or parsing error. + static PDDocument load15( + jni.JArray input, + jni.JString password, + jni.JObject keyStore, + jni.JString alias, + jni.JObject memUsageSetting, + ) { + return const $PDDocumentType().fromRef(_load15( + input.reference, + password.reference, + keyStore.reference, + alias.reference, + memUsageSetting.reference) + .object); + } + + static final _save = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDDocument__save") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void save(java.lang.String fileName) + /// + /// Save the document to a file. + /// + /// If encryption has been activated (with + /// \#protect(org.apache.pdfbox.pdmodel.encryption.ProtectionPolicy) protect(ProtectionPolicy)), + /// do not use the document after saving because the contents are now encrypted. + ///@param fileName The file to save as. + ///@throws IOException if the output could not be written + void save( + jni.JString fileName, + ) { + return _save(reference, fileName.reference).check(); + } + + static final _save1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDDocument__save1") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void save(java.io.File file) + /// + /// Save the document to a file. + /// + /// If encryption has been activated (with + /// \#protect(org.apache.pdfbox.pdmodel.encryption.ProtectionPolicy) protect(ProtectionPolicy)), + /// do not use the document after saving because the contents are now encrypted. + ///@param file The file to save as. + ///@throws IOException if the output could not be written + void save1( + jni.JObject file, + ) { + return _save1(reference, file.reference).check(); + } + + static final _save2 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDDocument__save2") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void save(java.io.OutputStream output) + /// + /// This will save the document to an output stream. + /// + /// If encryption has been activated (with + /// \#protect(org.apache.pdfbox.pdmodel.encryption.ProtectionPolicy) protect(ProtectionPolicy)), + /// do not use the document after saving because the contents are now encrypted. + ///@param output The stream to write to. It will be closed when done. It is recommended to wrap + /// it in a java.io.BufferedOutputStream, unless it is already buffered. + ///@throws IOException if the output could not be written + void save2( + jni.JObject output, + ) { + return _save2(reference, output.reference).check(); + } + + static final _saveIncremental = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDDocument__saveIncremental") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void saveIncremental(java.io.OutputStream output) + /// + /// Save the PDF as an incremental update. This is only possible if the PDF was loaded from a + /// file or a stream, not if the document was created in PDFBox itself. There must be a path of + /// objects that have COSUpdateInfo\#isNeedToBeUpdated() set, starting from the document + /// catalog. For signatures this is taken care by PDFBox itself. + /// + /// Other usages of this method are for experienced users only. You will usually never need it. + /// It is useful only if you are required to keep the current revision and append the changes. A + /// typical use case is changing a signed file without invalidating the signature. + ///@param output stream to write to. It will be closed when done. It + /// __must never__ point to the source file or that one will be + /// harmed! + ///@throws IOException if the output could not be written + ///@throws IllegalStateException if the document was not loaded from a file or a stream. + void saveIncremental( + jni.JObject output, + ) { + return _saveIncremental(reference, output.reference).check(); + } + + static final _saveIncremental1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>("PDDocument__saveIncremental1") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); + + /// from: public void saveIncremental(java.io.OutputStream output, java.util.Set objectsToWrite) + /// + /// Save the PDF as an incremental update. This is only possible if the PDF was loaded from a + /// file or a stream, not if the document was created in PDFBox itself. This allows to include + /// objects even if there is no path of objects that have + /// COSUpdateInfo\#isNeedToBeUpdated() set so the incremental update gets smaller. Only + /// dictionaries are supported; if you need to update other objects classes, then add their + /// parent dictionary. + /// + /// This method is for experienced users only. You will usually never need it. It is useful only + /// if you are required to keep the current revision and append the changes. A typical use case + /// is changing a signed file without invalidating the signature. To know which objects are + /// getting changed, you need to have some understanding of the PDF specification, and look at + /// the saved file with an editor to verify that you are updating the correct objects. You should + /// also inspect the page and document structures of the file with PDFDebugger. + ///@param output stream to write to. It will be closed when done. It + /// __must never__ point to the source file or that one will be harmed! + ///@param objectsToWrite objects that __must__ be part of the incremental saving. + ///@throws IOException if the output could not be written + ///@throws IllegalStateException if the document was not loaded from a file or a stream. + void saveIncremental1( + jni.JObject output, + jni.JSet objectsToWrite, + ) { + return _saveIncremental1( + reference, output.reference, objectsToWrite.reference) + .check(); + } + + static final _saveIncrementalForExternalSigning = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>>( + "PDDocument__saveIncrementalForExternalSigning") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public org.apache.pdfbox.pdmodel.interactive.digitalsignature.ExternalSigningSupport saveIncrementalForExternalSigning(java.io.OutputStream output) + /// The returned object must be released after use, by calling the [release] method. + /// + /// + /// __(This is a new feature for 2.0.3. The API for external signing might change based on feedback after release!)__ + /// + /// Save PDF incrementally without closing for external signature creation scenario. The general + /// sequence is: + ///
+  ///    PDDocument pdDocument = ...;
+  ///    OutputStream outputStream = ...;
+  ///    SignatureOptions signatureOptions = ...; // options to specify fine tuned signature options or null for defaults
+  ///    PDSignature pdSignature = ...;
+  ///
+  ///    // add signature parameters to be used when creating signature dictionary
+  ///    pdDocument.addSignature(pdSignature, signatureOptions);
+  ///    // prepare PDF for signing and obtain helper class to be used
+  ///    ExternalSigningSupport externalSigningSupport = pdDocument.saveIncrementalForExternalSigning(outputStream);
+  ///    // get data to be signed
+  ///    InputStream dataToBeSigned = externalSigningSupport.getContent();
+  ///    // invoke signature service
+  ///    byte[] signature = sign(dataToBeSigned);
+  ///    // set resulted CMS signature
+  ///    externalSigningSupport.setSignature(signature);
+  ///
+  ///    // last step is to close the document
+  ///    pdDocument.close();
+  /// 
+ /// + /// Note that after calling this method, only {@code close()} method may invoked for + /// {@code PDDocument} instance and only AFTER ExternalSigningSupport instance is used. + /// + /// + ///@param output stream to write the final PDF. It will be closed when the + /// document is closed. It __must never__ point to the source file + /// or that one will be harmed! + ///@return instance to be used for external signing and setting CMS signature + ///@throws IOException if the output could not be written + ///@throws IllegalStateException if the document was not loaded from a file or a stream or + /// signature options were not set. + jni.JObject saveIncrementalForExternalSigning( + jni.JObject output, + ) { + return const jni.JObjectType().fromRef( + _saveIncrementalForExternalSigning(reference, output.reference).object); + } + + static final _getPage = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Int32)>>("PDDocument__getPage") + .asFunction, int)>(); + + /// from: public org.apache.pdfbox.pdmodel.PDPage getPage(int pageIndex) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Returns the page at the given 0-based index. + /// + /// This method is too slow to get all the pages from a large PDF document + /// (1000 pages or more). For such documents, use the iterator of + /// PDDocument\#getPages() instead. + ///@param pageIndex the 0-based page index + ///@return the page at the given index. + jni.JObject getPage( + int pageIndex, + ) { + return const jni.JObjectType() + .fromRef(_getPage(reference, pageIndex).object); + } + + static final _getPages = jniLookup< + ffi + .NativeFunction)>>( + "PDDocument__getPages") + .asFunction)>(); + + /// from: public org.apache.pdfbox.pdmodel.PDPageTree getPages() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Returns the page tree. + ///@return the page tree + jni.JObject getPages() { + return const jni.JObjectType().fromRef(_getPages(reference).object); + } + + static final _getNumberOfPages = jniLookup< + ffi + .NativeFunction)>>( + "PDDocument__getNumberOfPages") + .asFunction)>(); + + /// from: public int getNumberOfPages() + /// + /// This will return the total page count of the PDF document. + ///@return The total number of pages in the PDF document. + int getNumberOfPages() { + return _getNumberOfPages(reference).integer; + } + + static final _close = jniLookup< + ffi + .NativeFunction)>>( + "PDDocument__close") + .asFunction)>(); + + /// from: public void close() + /// + /// This will close the underlying COSDocument object. + ///@throws IOException If there is an error releasing resources. + void close() { + return _close(reference).check(); + } + + static final _protect = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDDocument__protect") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void protect(org.apache.pdfbox.pdmodel.encryption.ProtectionPolicy policy) + /// + /// Protects the document with a protection policy. The document content will be really + /// encrypted when it will be saved. This method only marks the document for encryption. It also + /// calls \#setAllSecurityToBeRemoved(boolean) with a false argument if it was set to true + /// previously and logs a warning. + /// + /// Do not use the document after saving, because the structures are encrypted. + ///@see org.apache.pdfbox.pdmodel.encryption.StandardProtectionPolicy + ///@see org.apache.pdfbox.pdmodel.encryption.PublicKeyProtectionPolicy + ///@param policy The protection policy. + ///@throws IOException if there isn't any suitable security handler. + void protect( + jni.JObject policy, + ) { + return _protect(reference, policy.reference).check(); + } + + static final _getCurrentAccessPermission = jniLookup< + ffi + .NativeFunction)>>( + "PDDocument__getCurrentAccessPermission") + .asFunction)>(); + + /// from: public org.apache.pdfbox.pdmodel.encryption.AccessPermission getCurrentAccessPermission() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Returns the access permissions granted when the document was decrypted. If the document was not decrypted this + /// method returns the access permission for a document owner (ie can do everything). The returned object is in read + /// only mode so that permissions cannot be changed. Methods providing access to content should rely on this object + /// to verify if the current user is allowed to proceed. + ///@return the access permissions for the current user on the document. + jni.JObject getCurrentAccessPermission() { + return const jni.JObjectType() + .fromRef(_getCurrentAccessPermission(reference).object); + } + + static final _isAllSecurityToBeRemoved = jniLookup< + ffi + .NativeFunction)>>( + "PDDocument__isAllSecurityToBeRemoved") + .asFunction)>(); + + /// from: public boolean isAllSecurityToBeRemoved() + /// + /// Indicates if all security is removed or not when writing the pdf. + ///@return returns true if all security shall be removed otherwise false + bool isAllSecurityToBeRemoved() { + return _isAllSecurityToBeRemoved(reference).boolean; + } + + static final _setAllSecurityToBeRemoved = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Uint8)>>("PDDocument__setAllSecurityToBeRemoved") + .asFunction, int)>(); + + /// from: public void setAllSecurityToBeRemoved(boolean removeAllSecurity) + /// + /// Activates/Deactivates the removal of all security when writing the pdf. + ///@param removeAllSecurity remove all security if set to true + void setAllSecurityToBeRemoved( + bool removeAllSecurity, + ) { + return _setAllSecurityToBeRemoved(reference, removeAllSecurity ? 1 : 0) + .check(); + } + + static final _getDocumentId = jniLookup< + ffi + .NativeFunction)>>( + "PDDocument__getDocumentId") + .asFunction)>(); + + /// from: public java.lang.Long getDocumentId() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Provides the document ID. + ///@return the document ID + jni.JLong getDocumentId() { + return const jni.JLongType().fromRef(_getDocumentId(reference).object); + } + + static final _setDocumentId = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDDocument__setDocumentId") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void setDocumentId(java.lang.Long docId) + /// + /// Sets the document ID to the given value. + ///@param docId the new document ID + void setDocumentId( + jni.JLong docId, + ) { + return _setDocumentId(reference, docId.reference).check(); + } + + static final _getVersion = jniLookup< + ffi + .NativeFunction)>>( + "PDDocument__getVersion") + .asFunction)>(); + + /// from: public float getVersion() + /// + /// Returns the PDF specification version this document conforms to. + ///@return the PDF version (e.g. 1.4f) + double getVersion() { + return _getVersion(reference).float; + } + + static final _setVersion = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Float)>>("PDDocument__setVersion") + .asFunction, double)>(); + + /// from: public void setVersion(float newVersion) + /// + /// Sets the PDF specification version for this document. + ///@param newVersion the new PDF version (e.g. 1.4f) + void setVersion( + double newVersion, + ) { + return _setVersion(reference, newVersion).check(); + } + + static final _getResourceCache = jniLookup< + ffi + .NativeFunction)>>( + "PDDocument__getResourceCache") + .asFunction)>(); + + /// from: public org.apache.pdfbox.pdmodel.ResourceCache getResourceCache() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Returns the resource cache associated with this document, or null if there is none. + ///@return the resource cache or null. + jni.JObject getResourceCache() { + return const jni.JObjectType().fromRef(_getResourceCache(reference).object); + } + + static final _setResourceCache = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDDocument__setResourceCache") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void setResourceCache(org.apache.pdfbox.pdmodel.ResourceCache resourceCache) + /// + /// Sets the resource cache associated with this document. + ///@param resourceCache A resource cache, or null. + void setResourceCache( + jni.JObject resourceCache, + ) { + return _setResourceCache(reference, resourceCache.reference).check(); + } +} + +final class $PDDocumentType extends jni.JObjType { + const $PDDocumentType(); + + @override + String get signature => r"Lorg/apache/pdfbox/pdmodel/PDDocument;"; + + @override + PDDocument fromRef(jni.JObjectPtr ref) => PDDocument.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($PDDocumentType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($PDDocumentType) && other is $PDDocumentType; + } +} diff --git a/pkgs/jnigen/example/pdfbox_plugin/lib/src/third_party/org/apache/pdfbox/pdmodel/PDDocumentInformation.dart b/pkgs/jnigen/example/pdfbox_plugin/lib/src/third_party/org/apache/pdfbox/pdmodel/PDDocumentInformation.dart new file mode 100644 index 000000000..3c959e764 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/lib/src/third_party/org/apache/pdfbox/pdmodel/PDDocumentInformation.dart @@ -0,0 +1,524 @@ +// Generated from Apache PDFBox library which is licensed under the Apache License 2.0. +// The following copyright from the original authors applies. +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Autogenerated by jnigen. DO NOT EDIT! + +// ignore_for_file: annotate_overrides +// ignore_for_file: camel_case_extensions +// ignore_for_file: camel_case_types +// ignore_for_file: constant_identifier_names +// ignore_for_file: file_names +// ignore_for_file: lines_longer_than_80_chars +// ignore_for_file: no_leading_underscores_for_local_identifiers +// ignore_for_file: non_constant_identifier_names +// ignore_for_file: overridden_fields +// ignore_for_file: unnecessary_cast +// ignore_for_file: unused_element +// ignore_for_file: unused_field +// ignore_for_file: unused_import +// ignore_for_file: unused_local_variable +// ignore_for_file: unused_shown_name + +import "dart:isolate" show ReceivePort; +import "dart:ffi" as ffi; +import "package:jni/internal_helpers_for_jnigen.dart"; +import "package:jni/jni.dart" as jni; + +import "../../../../_init.dart"; + +/// from: org.apache.pdfbox.pdmodel.PDDocumentInformation +/// +/// This is the document metadata. Each getXXX method will return the entry if +/// it exists or null if it does not exist. If you pass in null for the setXXX +/// method then it will clear the value. +///@author Ben Litchfield +///@author Gerardo Ortiz +class PDDocumentInformation extends jni.JObject { + @override + late final jni.JObjType $type = type; + + PDDocumentInformation.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $PDDocumentInformationType(); + static final _new0 = jniLookup>( + "PDDocumentInformation__new0") + .asFunction(); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + /// + /// Default Constructor. + factory PDDocumentInformation() { + return PDDocumentInformation.fromRef(_new0().object); + } + + static final _new1 = jniLookup< + ffi + .NativeFunction)>>( + "PDDocumentInformation__new1") + .asFunction)>(); + + /// from: public void (org.apache.pdfbox.cos.COSDictionary dic) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Constructor that is used for a preexisting dictionary. + ///@param dic The underlying dictionary. + factory PDDocumentInformation.new1( + jni.JObject dic, + ) { + return PDDocumentInformation.fromRef(_new1(dic.reference).object); + } + + static final _getCOSObject = jniLookup< + ffi + .NativeFunction)>>( + "PDDocumentInformation__getCOSObject") + .asFunction)>(); + + /// from: public org.apache.pdfbox.cos.COSDictionary getCOSObject() + /// The returned object must be released after use, by calling the [release] method. + /// + /// This will get the underlying dictionary that this object wraps. + ///@return The underlying info dictionary. + jni.JObject getCOSObject() { + return const jni.JObjectType().fromRef(_getCOSObject(reference).object); + } + + static final _getPropertyStringValue = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>>( + "PDDocumentInformation__getPropertyStringValue") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public java.lang.Object getPropertyStringValue(java.lang.String propertyKey) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Return the properties String value. + /// + /// Allows to retrieve the + /// low level date for validation purposes. + /// + /// + ///@param propertyKey the dictionaries key + ///@return the properties value + jni.JObject getPropertyStringValue( + jni.JString propertyKey, + ) { + return const jni.JObjectType().fromRef( + _getPropertyStringValue(reference, propertyKey.reference).object); + } + + static final _getTitle = jniLookup< + ffi + .NativeFunction)>>( + "PDDocumentInformation__getTitle") + .asFunction)>(); + + /// from: public java.lang.String getTitle() + /// The returned object must be released after use, by calling the [release] method. + /// + /// This will get the title of the document. This will return null if no title exists. + ///@return The title of the document. + jni.JString getTitle() { + return const jni.JStringType().fromRef(_getTitle(reference).object); + } + + static final _setTitle = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDDocumentInformation__setTitle") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void setTitle(java.lang.String title) + /// + /// This will set the title of the document. + ///@param title The new title for the document. + void setTitle( + jni.JString title, + ) { + return _setTitle(reference, title.reference).check(); + } + + static final _getAuthor = jniLookup< + ffi + .NativeFunction)>>( + "PDDocumentInformation__getAuthor") + .asFunction)>(); + + /// from: public java.lang.String getAuthor() + /// The returned object must be released after use, by calling the [release] method. + /// + /// This will get the author of the document. This will return null if no author exists. + ///@return The author of the document. + jni.JString getAuthor() { + return const jni.JStringType().fromRef(_getAuthor(reference).object); + } + + static final _setAuthor = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDDocumentInformation__setAuthor") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void setAuthor(java.lang.String author) + /// + /// This will set the author of the document. + ///@param author The new author for the document. + void setAuthor( + jni.JString author, + ) { + return _setAuthor(reference, author.reference).check(); + } + + static final _getSubject = jniLookup< + ffi + .NativeFunction)>>( + "PDDocumentInformation__getSubject") + .asFunction)>(); + + /// from: public java.lang.String getSubject() + /// The returned object must be released after use, by calling the [release] method. + /// + /// This will get the subject of the document. This will return null if no subject exists. + ///@return The subject of the document. + jni.JString getSubject() { + return const jni.JStringType().fromRef(_getSubject(reference).object); + } + + static final _setSubject = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDDocumentInformation__setSubject") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void setSubject(java.lang.String subject) + /// + /// This will set the subject of the document. + ///@param subject The new subject for the document. + void setSubject( + jni.JString subject, + ) { + return _setSubject(reference, subject.reference).check(); + } + + static final _getKeywords = jniLookup< + ffi + .NativeFunction)>>( + "PDDocumentInformation__getKeywords") + .asFunction)>(); + + /// from: public java.lang.String getKeywords() + /// The returned object must be released after use, by calling the [release] method. + /// + /// This will get the keywords of the document. This will return null if no keywords exists. + ///@return The keywords of the document. + jni.JString getKeywords() { + return const jni.JStringType().fromRef(_getKeywords(reference).object); + } + + static final _setKeywords = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDDocumentInformation__setKeywords") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void setKeywords(java.lang.String keywords) + /// + /// This will set the keywords of the document. + ///@param keywords The new keywords for the document. + void setKeywords( + jni.JString keywords, + ) { + return _setKeywords(reference, keywords.reference).check(); + } + + static final _getCreator = jniLookup< + ffi + .NativeFunction)>>( + "PDDocumentInformation__getCreator") + .asFunction)>(); + + /// from: public java.lang.String getCreator() + /// The returned object must be released after use, by calling the [release] method. + /// + /// This will get the creator of the document. This will return null if no creator exists. + ///@return The creator of the document. + jni.JString getCreator() { + return const jni.JStringType().fromRef(_getCreator(reference).object); + } + + static final _setCreator = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDDocumentInformation__setCreator") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void setCreator(java.lang.String creator) + /// + /// This will set the creator of the document. + ///@param creator The new creator for the document. + void setCreator( + jni.JString creator, + ) { + return _setCreator(reference, creator.reference).check(); + } + + static final _getProducer = jniLookup< + ffi + .NativeFunction)>>( + "PDDocumentInformation__getProducer") + .asFunction)>(); + + /// from: public java.lang.String getProducer() + /// The returned object must be released after use, by calling the [release] method. + /// + /// This will get the producer of the document. This will return null if no producer exists. + ///@return The producer of the document. + jni.JString getProducer() { + return const jni.JStringType().fromRef(_getProducer(reference).object); + } + + static final _setProducer = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDDocumentInformation__setProducer") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void setProducer(java.lang.String producer) + /// + /// This will set the producer of the document. + ///@param producer The new producer for the document. + void setProducer( + jni.JString producer, + ) { + return _setProducer(reference, producer.reference).check(); + } + + static final _getCreationDate = jniLookup< + ffi + .NativeFunction)>>( + "PDDocumentInformation__getCreationDate") + .asFunction)>(); + + /// from: public java.util.Calendar getCreationDate() + /// The returned object must be released after use, by calling the [release] method. + /// + /// This will get the creation date of the document. This will return null if no creation date exists. + ///@return The creation date of the document. + jni.JObject getCreationDate() { + return const jni.JObjectType().fromRef(_getCreationDate(reference).object); + } + + static final _setCreationDate = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>>( + "PDDocumentInformation__setCreationDate") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void setCreationDate(java.util.Calendar date) + /// + /// This will set the creation date of the document. + ///@param date The new creation date for the document. + void setCreationDate( + jni.JObject date, + ) { + return _setCreationDate(reference, date.reference).check(); + } + + static final _getModificationDate = jniLookup< + ffi + .NativeFunction)>>( + "PDDocumentInformation__getModificationDate") + .asFunction)>(); + + /// from: public java.util.Calendar getModificationDate() + /// The returned object must be released after use, by calling the [release] method. + /// + /// This will get the modification date of the document. This will return null if no modification date exists. + ///@return The modification date of the document. + jni.JObject getModificationDate() { + return const jni.JObjectType() + .fromRef(_getModificationDate(reference).object); + } + + static final _setModificationDate = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>>( + "PDDocumentInformation__setModificationDate") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void setModificationDate(java.util.Calendar date) + /// + /// This will set the modification date of the document. + ///@param date The new modification date for the document. + void setModificationDate( + jni.JObject date, + ) { + return _setModificationDate(reference, date.reference).check(); + } + + static final _getTrapped = jniLookup< + ffi + .NativeFunction)>>( + "PDDocumentInformation__getTrapped") + .asFunction)>(); + + /// from: public java.lang.String getTrapped() + /// The returned object must be released after use, by calling the [release] method. + /// + /// This will get the trapped value for the document. + /// This will return null if one is not found. + ///@return The trapped value for the document. + jni.JString getTrapped() { + return const jni.JStringType().fromRef(_getTrapped(reference).object); + } + + static final _getMetadataKeys = jniLookup< + ffi + .NativeFunction)>>( + "PDDocumentInformation__getMetadataKeys") + .asFunction)>(); + + /// from: public java.util.Set getMetadataKeys() + /// The returned object must be released after use, by calling the [release] method. + /// + /// This will get the keys of all metadata information fields for the document. + ///@return all metadata key strings. + ///@since Apache PDFBox 1.3.0 + jni.JSet getMetadataKeys() { + return const jni.JSetType(jni.JStringType()) + .fromRef(_getMetadataKeys(reference).object); + } + + static final _getCustomMetadataValue = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>>( + "PDDocumentInformation__getCustomMetadataValue") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public java.lang.String getCustomMetadataValue(java.lang.String fieldName) + /// The returned object must be released after use, by calling the [release] method. + /// + /// This will get the value of a custom metadata information field for the document. + /// This will return null if one is not found. + ///@param fieldName Name of custom metadata field from pdf document. + ///@return String Value of metadata field + jni.JString getCustomMetadataValue( + jni.JString fieldName, + ) { + return const jni.JStringType().fromRef( + _getCustomMetadataValue(reference, fieldName.reference).object); + } + + static final _setCustomMetadataValue = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer, ffi.Pointer)>>( + "PDDocumentInformation__setCustomMetadataValue") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); + + /// from: public void setCustomMetadataValue(java.lang.String fieldName, java.lang.String fieldValue) + /// + /// Set the custom metadata value. + ///@param fieldName The name of the custom metadata field. + ///@param fieldValue The value to the custom metadata field. + void setCustomMetadataValue( + jni.JString fieldName, + jni.JString fieldValue, + ) { + return _setCustomMetadataValue( + reference, fieldName.reference, fieldValue.reference) + .check(); + } + + static final _setTrapped = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDDocumentInformation__setTrapped") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void setTrapped(java.lang.String value) + /// + /// This will set the trapped of the document. This will be + /// 'True', 'False', or 'Unknown'. + ///@param value The new trapped value for the document. + ///@throws IllegalArgumentException if the parameter is invalid. + void setTrapped( + jni.JString value, + ) { + return _setTrapped(reference, value.reference).check(); + } +} + +final class $PDDocumentInformationType + extends jni.JObjType { + const $PDDocumentInformationType(); + + @override + String get signature => r"Lorg/apache/pdfbox/pdmodel/PDDocumentInformation;"; + + @override + PDDocumentInformation fromRef(jni.JObjectPtr ref) => + PDDocumentInformation.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($PDDocumentInformationType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($PDDocumentInformationType) && + other is $PDDocumentInformationType; + } +} diff --git a/pkgs/jnigen/example/pdfbox_plugin/lib/src/third_party/org/apache/pdfbox/pdmodel/_package.dart b/pkgs/jnigen/example/pdfbox_plugin/lib/src/third_party/org/apache/pdfbox/pdmodel/_package.dart new file mode 100644 index 000000000..d2b39294a --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/lib/src/third_party/org/apache/pdfbox/pdmodel/_package.dart @@ -0,0 +1,2 @@ +export "PDDocument.dart"; +export "PDDocumentInformation.dart"; diff --git a/pkgs/jnigen/example/pdfbox_plugin/lib/src/third_party/org/apache/pdfbox/text/PDFTextStripper.dart b/pkgs/jnigen/example/pdfbox_plugin/lib/src/third_party/org/apache/pdfbox/text/PDFTextStripper.dart new file mode 100644 index 000000000..930240b70 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/lib/src/third_party/org/apache/pdfbox/text/PDFTextStripper.dart @@ -0,0 +1,1424 @@ +// Generated from Apache PDFBox library which is licensed under the Apache License 2.0. +// The following copyright from the original authors applies. +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Autogenerated by jnigen. DO NOT EDIT! + +// ignore_for_file: annotate_overrides +// ignore_for_file: camel_case_extensions +// ignore_for_file: camel_case_types +// ignore_for_file: constant_identifier_names +// ignore_for_file: file_names +// ignore_for_file: lines_longer_than_80_chars +// ignore_for_file: no_leading_underscores_for_local_identifiers +// ignore_for_file: non_constant_identifier_names +// ignore_for_file: overridden_fields +// ignore_for_file: unnecessary_cast +// ignore_for_file: unused_element +// ignore_for_file: unused_field +// ignore_for_file: unused_import +// ignore_for_file: unused_local_variable +// ignore_for_file: unused_shown_name + +import "dart:isolate" show ReceivePort; +import "dart:ffi" as ffi; +import "package:jni/internal_helpers_for_jnigen.dart"; +import "package:jni/jni.dart" as jni; + +import "../pdmodel/PDDocument.dart" as pddocument_; +import "../../../../_init.dart"; + +/// from: org.apache.pdfbox.text.PDFTextStripper +/// +/// This class will take a pdf document and strip out all of the text and ignore the formatting and such. Please note; it +/// is up to clients of this class to verify that a specific user has the correct permissions to extract text from the +/// PDF document. +/// +/// The basic flow of this process is that we get a document and use a series of processXXX() functions that work on +/// smaller and smaller chunks of the page. Eventually, we fully process each page and then print it. +///@author Ben Litchfield +class PDFTextStripper extends jni.JObject { + @override + late final jni.JObjType $type = type; + + PDFTextStripper.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $PDFTextStripperType(); + static final _get_LINE_SEPARATOR = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>>("get_PDFTextStripper__LINE_SEPARATOR") + .asFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>(); + + /// from: protected final java.lang.String LINE_SEPARATOR + /// The returned object must be released after use, by calling the [release] method. + /// + /// The platform's line separator. + jni.JString get LINE_SEPARATOR => + const jni.JStringType().fromRef(_get_LINE_SEPARATOR(reference).object); + + static final _get_charactersByArticle = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>>("get_PDFTextStripper__charactersByArticle") + .asFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>(); + + static final _set_charactersByArticle = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, ffi.Pointer)>>( + "set_PDFTextStripper__charactersByArticle") + .asFunction< + jni.JniResult Function(jni.JObjectPtr, ffi.Pointer)>(); + + /// from: protected java.util.ArrayList> charactersByArticle + /// The returned object must be released after use, by calling the [release] method. + /// + /// The charactersByArticle is used to extract text by article divisions. For example a PDF that has two columns like + /// a newspaper, we want to extract the first column and then the second column. In this example the PDF would have 2 + /// beads(or articles), one for each column. The size of the charactersByArticle would be 5, because not all text on + /// the screen will fall into one of the articles. The five divisions are shown below + /// + /// Text before first article + /// first article text + /// text between first article and second article + /// second article text + /// text after second article + /// + /// Most PDFs won't have any beads, so charactersByArticle will contain a single entry. + jni.JObject get charactersByArticle => const jni.JObjectType() + .fromRef(_get_charactersByArticle(reference).object); + + /// from: protected java.util.ArrayList> charactersByArticle + /// The returned object must be released after use, by calling the [release] method. + /// + /// The charactersByArticle is used to extract text by article divisions. For example a PDF that has two columns like + /// a newspaper, we want to extract the first column and then the second column. In this example the PDF would have 2 + /// beads(or articles), one for each column. The size of the charactersByArticle would be 5, because not all text on + /// the screen will fall into one of the articles. The five divisions are shown below + /// + /// Text before first article + /// first article text + /// text between first article and second article + /// second article text + /// text after second article + /// + /// Most PDFs won't have any beads, so charactersByArticle will contain a single entry. + set charactersByArticle(jni.JObject value) => + _set_charactersByArticle(reference, value.reference).check(); + + static final _get_document = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>>("get_PDFTextStripper__document") + .asFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>(); + + static final _set_document = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(jni.JObjectPtr, + ffi.Pointer)>>("set_PDFTextStripper__document") + .asFunction< + jni.JniResult Function(jni.JObjectPtr, ffi.Pointer)>(); + + /// from: protected org.apache.pdfbox.pdmodel.PDDocument document + /// The returned object must be released after use, by calling the [release] method. + pddocument_.PDDocument get document => const pddocument_.$PDDocumentType() + .fromRef(_get_document(reference).object); + + /// from: protected org.apache.pdfbox.pdmodel.PDDocument document + /// The returned object must be released after use, by calling the [release] method. + set document(pddocument_.PDDocument value) => + _set_document(reference, value.reference).check(); + + static final _get_output = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>>("get_PDFTextStripper__output") + .asFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>(); + + static final _set_output = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(jni.JObjectPtr, + ffi.Pointer)>>("set_PDFTextStripper__output") + .asFunction< + jni.JniResult Function(jni.JObjectPtr, ffi.Pointer)>(); + + /// from: protected java.io.Writer output + /// The returned object must be released after use, by calling the [release] method. + jni.JObject get output => + const jni.JObjectType().fromRef(_get_output(reference).object); + + /// from: protected java.io.Writer output + /// The returned object must be released after use, by calling the [release] method. + set output(jni.JObject value) => + _set_output(reference, value.reference).check(); + + static final _new0 = jniLookup>( + "PDFTextStripper__new0") + .asFunction(); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + /// + /// Instantiate a new PDFTextStripper object. + ///@throws IOException If there is an error loading the properties. + factory PDFTextStripper() { + return PDFTextStripper.fromRef(_new0().object); + } + + static final _getText = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDFTextStripper__getText") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public java.lang.String getText(org.apache.pdfbox.pdmodel.PDDocument doc) + /// The returned object must be released after use, by calling the [release] method. + /// + /// This will return the text of a document. See writeText.
+ /// NOTE: The document must not be encrypted when coming into this method. + /// + /// IMPORTANT: By default, text extraction is done in the same sequence as the text in the PDF page content stream. + /// PDF is a graphic format, not a text format, and unlike HTML, it has no requirements that text one on page + /// be rendered in a certain order. The order is the one that was determined by the software that created the + /// PDF. To get text sorted from left to right and top to botton, use \#setSortByPosition(boolean). + ///@param doc The document to get the text from. + ///@return The text of the PDF document. + ///@throws IOException if the doc state is invalid or it is encrypted. + jni.JString getText( + pddocument_.PDDocument doc, + ) { + return const jni.JStringType() + .fromRef(_getText(reference, doc.reference).object); + } + + static final _writeText = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>("PDFTextStripper__writeText") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); + + /// from: public void writeText(org.apache.pdfbox.pdmodel.PDDocument doc, java.io.Writer outputStream) + /// + /// This will take a PDDocument and write the text of that document to the print writer. + ///@param doc The document to get the data from. + ///@param outputStream The location to put the text. + ///@throws IOException If the doc is in an invalid state. + void writeText( + pddocument_.PDDocument doc, + jni.JObject outputStream, + ) { + return _writeText(reference, doc.reference, outputStream.reference).check(); + } + + static final _processPages = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDFTextStripper__processPages") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: protected void processPages(org.apache.pdfbox.pdmodel.PDPageTree pages) + /// + /// This will process all of the pages and the text that is in them. + ///@param pages The pages object in the document. + ///@throws IOException If there is an error parsing the text. + void processPages( + jni.JObject pages, + ) { + return _processPages(reference, pages.reference).check(); + } + + static final _startDocument = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDFTextStripper__startDocument") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: protected void startDocument(org.apache.pdfbox.pdmodel.PDDocument document) + /// + /// This method is available for subclasses of this class. It will be called before processing of the document start. + ///@param document The PDF document that is being processed. + ///@throws IOException If an IO error occurs. + void startDocument( + pddocument_.PDDocument document, + ) { + return _startDocument(reference, document.reference).check(); + } + + static final _endDocument = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDFTextStripper__endDocument") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: protected void endDocument(org.apache.pdfbox.pdmodel.PDDocument document) + /// + /// This method is available for subclasses of this class. It will be called after processing of the document + /// finishes. + ///@param document The PDF document that is being processed. + ///@throws IOException If an IO error occurs. + void endDocument( + pddocument_.PDDocument document, + ) { + return _endDocument(reference, document.reference).check(); + } + + static final _processPage = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDFTextStripper__processPage") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void processPage(org.apache.pdfbox.pdmodel.PDPage page) + /// + /// This will process the contents of a page. + ///@param page The page to process. + ///@throws IOException If there is an error processing the page. + void processPage( + jni.JObject page, + ) { + return _processPage(reference, page.reference).check(); + } + + static final _startArticle = jniLookup< + ffi + .NativeFunction)>>( + "PDFTextStripper__startArticle") + .asFunction)>(); + + /// from: protected void startArticle() + /// + /// Start a new article, which is typically defined as a column on a single page (also referred to as a bead). This + /// assumes that the primary direction of text is left to right. Default implementation is to do nothing. Subclasses + /// may provide additional information. + ///@throws IOException If there is any error writing to the stream. + void startArticle() { + return _startArticle(reference).check(); + } + + static final _startArticle1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Uint8)>>("PDFTextStripper__startArticle1") + .asFunction, int)>(); + + /// from: protected void startArticle(boolean isLTR) + /// + /// Start a new article, which is typically defined as a column on a single page (also referred to as a bead). + /// Default implementation is to do nothing. Subclasses may provide additional information. + ///@param isLTR true if primary direction of text is left to right. + ///@throws IOException If there is any error writing to the stream. + void startArticle1( + bool isLTR, + ) { + return _startArticle1(reference, isLTR ? 1 : 0).check(); + } + + static final _endArticle = jniLookup< + ffi + .NativeFunction)>>( + "PDFTextStripper__endArticle") + .asFunction)>(); + + /// from: protected void endArticle() + /// + /// End an article. Default implementation is to do nothing. Subclasses may provide additional information. + ///@throws IOException If there is any error writing to the stream. + void endArticle() { + return _endArticle(reference).check(); + } + + static final _startPage = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDFTextStripper__startPage") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: protected void startPage(org.apache.pdfbox.pdmodel.PDPage page) + /// + /// Start a new page. Default implementation is to do nothing. Subclasses may provide additional information. + ///@param page The page we are about to process. + ///@throws IOException If there is any error writing to the stream. + void startPage( + jni.JObject page, + ) { + return _startPage(reference, page.reference).check(); + } + + static final _endPage = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDFTextStripper__endPage") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: protected void endPage(org.apache.pdfbox.pdmodel.PDPage page) + /// + /// End a page. Default implementation is to do nothing. Subclasses may provide additional information. + ///@param page The page we are about to process. + ///@throws IOException If there is any error writing to the stream. + void endPage( + jni.JObject page, + ) { + return _endPage(reference, page.reference).check(); + } + + static final _writePage = jniLookup< + ffi + .NativeFunction)>>( + "PDFTextStripper__writePage") + .asFunction)>(); + + /// from: protected void writePage() + /// + /// This will print the text of the processed page to "output". It will estimate, based on the coordinates of the + /// text, where newlines and word spacings should be placed. The text will be sorted only if that feature was + /// enabled. + ///@throws IOException If there is an error writing the text. + void writePage() { + return _writePage(reference).check(); + } + + static final _writeLineSeparator = jniLookup< + ffi + .NativeFunction)>>( + "PDFTextStripper__writeLineSeparator") + .asFunction)>(); + + /// from: protected void writeLineSeparator() + /// + /// Write the line separator value to the output stream. + ///@throws IOException If there is a problem writing out the line separator to the document. + void writeLineSeparator() { + return _writeLineSeparator(reference).check(); + } + + static final _writeWordSeparator = jniLookup< + ffi + .NativeFunction)>>( + "PDFTextStripper__writeWordSeparator") + .asFunction)>(); + + /// from: protected void writeWordSeparator() + /// + /// Write the word separator value to the output stream. + ///@throws IOException If there is a problem writing out the word separator to the document. + void writeWordSeparator() { + return _writeWordSeparator(reference).check(); + } + + static final _writeCharacters = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDFTextStripper__writeCharacters") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: protected void writeCharacters(org.apache.pdfbox.text.TextPosition text) + /// + /// Write the string in TextPosition to the output stream. + ///@param text The text to write to the stream. + ///@throws IOException If there is an error when writing the text. + void writeCharacters( + jni.JObject text, + ) { + return _writeCharacters(reference, text.reference).check(); + } + + static final _writeString = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>("PDFTextStripper__writeString") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); + + /// from: protected void writeString(java.lang.String text, java.util.List textPositions) + /// + /// Write a Java string to the output stream. The default implementation will ignore the textPositions + /// and just calls \#writeString(String). + ///@param text The text to write to the stream. + ///@param textPositions The TextPositions belonging to the text. + ///@throws IOException If there is an error when writing the text. + void writeString( + jni.JString text, + jni.JList textPositions, + ) { + return _writeString(reference, text.reference, textPositions.reference) + .check(); + } + + static final _writeString1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDFTextStripper__writeString1") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: protected void writeString(java.lang.String text) + /// + /// Write a Java string to the output stream. + ///@param text The text to write to the stream. + ///@throws IOException If there is an error when writing the text. + void writeString1( + jni.JString text, + ) { + return _writeString1(reference, text.reference).check(); + } + + static final _processTextPosition = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>>( + "PDFTextStripper__processTextPosition") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: protected void processTextPosition(org.apache.pdfbox.text.TextPosition text) + /// + /// This will process a TextPosition object and add the text to the list of characters on a page. It takes care of + /// overlapping text. + ///@param text The text to process. + void processTextPosition( + jni.JObject text, + ) { + return _processTextPosition(reference, text.reference).check(); + } + + static final _getStartPage = jniLookup< + ffi + .NativeFunction)>>( + "PDFTextStripper__getStartPage") + .asFunction)>(); + + /// from: public int getStartPage() + /// + /// This is the page that the text extraction will start on. The pages start at page 1. For example in a 5 page PDF + /// document, if the start page is 1 then all pages will be extracted. If the start page is 4 then pages 4 and 5 will + /// be extracted. The default value is 1. + ///@return Value of property startPage. + int getStartPage() { + return _getStartPage(reference).integer; + } + + static final _setStartPage = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Int32)>>("PDFTextStripper__setStartPage") + .asFunction, int)>(); + + /// from: public void setStartPage(int startPageValue) + /// + /// This will set the first page to be extracted by this class. + ///@param startPageValue New value of 1-based startPage property. + void setStartPage( + int startPageValue, + ) { + return _setStartPage(reference, startPageValue).check(); + } + + static final _getEndPage = jniLookup< + ffi + .NativeFunction)>>( + "PDFTextStripper__getEndPage") + .asFunction)>(); + + /// from: public int getEndPage() + /// + /// This will get the last page that will be extracted. This is inclusive, for example if a 5 page PDF an endPage + /// value of 5 would extract the entire document, an end page of 2 would extract pages 1 and 2. This defaults to + /// Integer.MAX_VALUE such that all pages of the pdf will be extracted. + ///@return Value of property endPage. + int getEndPage() { + return _getEndPage(reference).integer; + } + + static final _setEndPage = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Int32)>>("PDFTextStripper__setEndPage") + .asFunction, int)>(); + + /// from: public void setEndPage(int endPageValue) + /// + /// This will set the last page to be extracted by this class. + ///@param endPageValue New value of 1-based endPage property. + void setEndPage( + int endPageValue, + ) { + return _setEndPage(reference, endPageValue).check(); + } + + static final _setLineSeparator = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDFTextStripper__setLineSeparator") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void setLineSeparator(java.lang.String separator) + /// + /// Set the desired line separator for output text. The line.separator system property is used if the line separator + /// preference is not set explicitly using this method. + ///@param separator The desired line separator string. + void setLineSeparator( + jni.JString separator, + ) { + return _setLineSeparator(reference, separator.reference).check(); + } + + static final _getLineSeparator = jniLookup< + ffi + .NativeFunction)>>( + "PDFTextStripper__getLineSeparator") + .asFunction)>(); + + /// from: public java.lang.String getLineSeparator() + /// The returned object must be released after use, by calling the [release] method. + /// + /// This will get the line separator. + ///@return The desired line separator string. + jni.JString getLineSeparator() { + return const jni.JStringType().fromRef(_getLineSeparator(reference).object); + } + + static final _getWordSeparator = jniLookup< + ffi + .NativeFunction)>>( + "PDFTextStripper__getWordSeparator") + .asFunction)>(); + + /// from: public java.lang.String getWordSeparator() + /// The returned object must be released after use, by calling the [release] method. + /// + /// This will get the word separator. + ///@return The desired word separator string. + jni.JString getWordSeparator() { + return const jni.JStringType().fromRef(_getWordSeparator(reference).object); + } + + static final _setWordSeparator = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDFTextStripper__setWordSeparator") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void setWordSeparator(java.lang.String separator) + /// + /// Set the desired word separator for output text. The PDFBox text extraction algorithm will output a space + /// character if there is enough space between two words. By default a space character is used. If you need and + /// accurate count of characters that are found in a PDF document then you might want to set the word separator to + /// the empty string. + ///@param separator The desired page separator string. + void setWordSeparator( + jni.JString separator, + ) { + return _setWordSeparator(reference, separator.reference).check(); + } + + static final _getSuppressDuplicateOverlappingText = jniLookup< + ffi + .NativeFunction)>>( + "PDFTextStripper__getSuppressDuplicateOverlappingText") + .asFunction)>(); + + /// from: public boolean getSuppressDuplicateOverlappingText() + /// + /// @return Returns the suppressDuplicateOverlappingText. + bool getSuppressDuplicateOverlappingText() { + return _getSuppressDuplicateOverlappingText(reference).boolean; + } + + static final _getCurrentPageNo = jniLookup< + ffi + .NativeFunction)>>( + "PDFTextStripper__getCurrentPageNo") + .asFunction)>(); + + /// from: protected int getCurrentPageNo() + /// + /// Get the current page number that is being processed. + ///@return A 1 based number representing the current page. + int getCurrentPageNo() { + return _getCurrentPageNo(reference).integer; + } + + static final _getOutput = jniLookup< + ffi + .NativeFunction)>>( + "PDFTextStripper__getOutput") + .asFunction)>(); + + /// from: protected java.io.Writer getOutput() + /// The returned object must be released after use, by calling the [release] method. + /// + /// The output stream that is being written to. + ///@return The stream that output is being written to. + jni.JObject getOutput() { + return const jni.JObjectType().fromRef(_getOutput(reference).object); + } + + static final _getCharactersByArticle = jniLookup< + ffi + .NativeFunction)>>( + "PDFTextStripper__getCharactersByArticle") + .asFunction)>(); + + /// from: protected java.util.List> getCharactersByArticle() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Character strings are grouped by articles. It is quite common that there will only be a single article. This + /// returns a List that contains List objects, the inner lists will contain TextPosition objects. + ///@return A double List of TextPositions for all text strings on the page. + jni.JList> getCharactersByArticle() { + return const jni.JListType(jni.JListType(jni.JObjectType())) + .fromRef(_getCharactersByArticle(reference).object); + } + + static final _setSuppressDuplicateOverlappingText = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, ffi.Uint8)>>( + "PDFTextStripper__setSuppressDuplicateOverlappingText") + .asFunction, int)>(); + + /// from: public void setSuppressDuplicateOverlappingText(boolean suppressDuplicateOverlappingTextValue) + /// + /// By default the text stripper will attempt to remove text that overlapps each other. Word paints the same + /// character several times in order to make it look bold. By setting this to false all text will be extracted, which + /// means that certain sections will be duplicated, but better performance will be noticed. + ///@param suppressDuplicateOverlappingTextValue The suppressDuplicateOverlappingText to set. + void setSuppressDuplicateOverlappingText( + bool suppressDuplicateOverlappingTextValue, + ) { + return _setSuppressDuplicateOverlappingText( + reference, suppressDuplicateOverlappingTextValue ? 1 : 0) + .check(); + } + + static final _getSeparateByBeads = jniLookup< + ffi + .NativeFunction)>>( + "PDFTextStripper__getSeparateByBeads") + .asFunction)>(); + + /// from: public boolean getSeparateByBeads() + /// + /// This will tell if the text stripper should separate by beads. + ///@return If the text will be grouped by beads. + bool getSeparateByBeads() { + return _getSeparateByBeads(reference).boolean; + } + + static final _setShouldSeparateByBeads = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Uint8)>>("PDFTextStripper__setShouldSeparateByBeads") + .asFunction, int)>(); + + /// from: public void setShouldSeparateByBeads(boolean aShouldSeparateByBeads) + /// + /// Set if the text stripper should group the text output by a list of beads. The default value is true! + ///@param aShouldSeparateByBeads The new grouping of beads. + void setShouldSeparateByBeads( + bool aShouldSeparateByBeads, + ) { + return _setShouldSeparateByBeads(reference, aShouldSeparateByBeads ? 1 : 0) + .check(); + } + + static final _getEndBookmark = jniLookup< + ffi + .NativeFunction)>>( + "PDFTextStripper__getEndBookmark") + .asFunction)>(); + + /// from: public org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDOutlineItem getEndBookmark() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Get the bookmark where text extraction should end, inclusive. Default is null. + ///@return The ending bookmark. + jni.JObject getEndBookmark() { + return const jni.JObjectType().fromRef(_getEndBookmark(reference).object); + } + + static final _setEndBookmark = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDFTextStripper__setEndBookmark") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void setEndBookmark(org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDOutlineItem aEndBookmark) + /// + /// Set the bookmark where the text extraction should stop. + ///@param aEndBookmark The ending bookmark. + void setEndBookmark( + jni.JObject aEndBookmark, + ) { + return _setEndBookmark(reference, aEndBookmark.reference).check(); + } + + static final _getStartBookmark = jniLookup< + ffi + .NativeFunction)>>( + "PDFTextStripper__getStartBookmark") + .asFunction)>(); + + /// from: public org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDOutlineItem getStartBookmark() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Get the bookmark where text extraction should start, inclusive. Default is null. + ///@return The starting bookmark. + jni.JObject getStartBookmark() { + return const jni.JObjectType().fromRef(_getStartBookmark(reference).object); + } + + static final _setStartBookmark = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDFTextStripper__setStartBookmark") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void setStartBookmark(org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDOutlineItem aStartBookmark) + /// + /// Set the bookmark where text extraction should start, inclusive. + ///@param aStartBookmark The starting bookmark. + void setStartBookmark( + jni.JObject aStartBookmark, + ) { + return _setStartBookmark(reference, aStartBookmark.reference).check(); + } + + static final _getAddMoreFormatting = jniLookup< + ffi + .NativeFunction)>>( + "PDFTextStripper__getAddMoreFormatting") + .asFunction)>(); + + /// from: public boolean getAddMoreFormatting() + /// + /// This will tell if the text stripper should add some more text formatting. + ///@return true if some more text formatting will be added + bool getAddMoreFormatting() { + return _getAddMoreFormatting(reference).boolean; + } + + static final _setAddMoreFormatting = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Uint8)>>("PDFTextStripper__setAddMoreFormatting") + .asFunction, int)>(); + + /// from: public void setAddMoreFormatting(boolean newAddMoreFormatting) + /// + /// There will some additional text formatting be added if addMoreFormatting is set to true. Default is false. + ///@param newAddMoreFormatting Tell PDFBox to add some more text formatting + void setAddMoreFormatting( + bool newAddMoreFormatting, + ) { + return _setAddMoreFormatting(reference, newAddMoreFormatting ? 1 : 0) + .check(); + } + + static final _getSortByPosition = jniLookup< + ffi + .NativeFunction)>>( + "PDFTextStripper__getSortByPosition") + .asFunction)>(); + + /// from: public boolean getSortByPosition() + /// + /// This will tell if the text stripper should sort the text tokens before writing to the stream. + ///@return true If the text tokens will be sorted before being written. + bool getSortByPosition() { + return _getSortByPosition(reference).boolean; + } + + static final _setSortByPosition = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Uint8)>>("PDFTextStripper__setSortByPosition") + .asFunction, int)>(); + + /// from: public void setSortByPosition(boolean newSortByPosition) + /// + /// The order of the text tokens in a PDF file may not be in the same as they appear visually on the screen. For + /// example, a PDF writer may write out all text by font, so all bold or larger text, then make a second pass and + /// write out the normal text.
+ /// The default is to __not__ sort by position.
+ ///
+ /// A PDF writer could choose to write each character in a different order. By default PDFBox does __not__ sort + /// the text tokens before processing them due to performance reasons. + ///@param newSortByPosition Tell PDFBox to sort the text positions. + void setSortByPosition( + bool newSortByPosition, + ) { + return _setSortByPosition(reference, newSortByPosition ? 1 : 0).check(); + } + + static final _getSpacingTolerance = jniLookup< + ffi + .NativeFunction)>>( + "PDFTextStripper__getSpacingTolerance") + .asFunction)>(); + + /// from: public float getSpacingTolerance() + /// + /// Get the current space width-based tolerance value that is being used to estimate where spaces in text should be + /// added. Note that the default value for this has been determined from trial and error. + ///@return The current tolerance / scaling factor + double getSpacingTolerance() { + return _getSpacingTolerance(reference).float; + } + + static final _setSpacingTolerance = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Float)>>("PDFTextStripper__setSpacingTolerance") + .asFunction, double)>(); + + /// from: public void setSpacingTolerance(float spacingToleranceValue) + /// + /// Set the space width-based tolerance value that is used to estimate where spaces in text should be added. Note + /// that the default value for this has been determined from trial and error. Setting this value larger will reduce + /// the number of spaces added. + ///@param spacingToleranceValue tolerance / scaling factor to use + void setSpacingTolerance( + double spacingToleranceValue, + ) { + return _setSpacingTolerance(reference, spacingToleranceValue).check(); + } + + static final _getAverageCharTolerance = jniLookup< + ffi + .NativeFunction)>>( + "PDFTextStripper__getAverageCharTolerance") + .asFunction)>(); + + /// from: public float getAverageCharTolerance() + /// + /// Get the current character width-based tolerance value that is being used to estimate where spaces in text should + /// be added. Note that the default value for this has been determined from trial and error. + ///@return The current tolerance / scaling factor + double getAverageCharTolerance() { + return _getAverageCharTolerance(reference).float; + } + + static final _setAverageCharTolerance = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Float)>>("PDFTextStripper__setAverageCharTolerance") + .asFunction, double)>(); + + /// from: public void setAverageCharTolerance(float averageCharToleranceValue) + /// + /// Set the character width-based tolerance value that is used to estimate where spaces in text should be added. Note + /// that the default value for this has been determined from trial and error. Setting this value larger will reduce + /// the number of spaces added. + ///@param averageCharToleranceValue average tolerance / scaling factor to use + void setAverageCharTolerance( + double averageCharToleranceValue, + ) { + return _setAverageCharTolerance(reference, averageCharToleranceValue) + .check(); + } + + static final _getIndentThreshold = jniLookup< + ffi + .NativeFunction)>>( + "PDFTextStripper__getIndentThreshold") + .asFunction)>(); + + /// from: public float getIndentThreshold() + /// + /// returns the multiple of whitespace character widths for the current text which the current line start can be + /// indented from the previous line start beyond which the current line start is considered to be a paragraph start. + ///@return the number of whitespace character widths to use when detecting paragraph indents. + double getIndentThreshold() { + return _getIndentThreshold(reference).float; + } + + static final _setIndentThreshold = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Float)>>("PDFTextStripper__setIndentThreshold") + .asFunction, double)>(); + + /// from: public void setIndentThreshold(float indentThresholdValue) + /// + /// sets the multiple of whitespace character widths for the current text which the current line start can be + /// indented from the previous line start beyond which the current line start is considered to be a paragraph start. + /// The default value is 2.0. + ///@param indentThresholdValue the number of whitespace character widths to use when detecting paragraph indents. + void setIndentThreshold( + double indentThresholdValue, + ) { + return _setIndentThreshold(reference, indentThresholdValue).check(); + } + + static final _getDropThreshold = jniLookup< + ffi + .NativeFunction)>>( + "PDFTextStripper__getDropThreshold") + .asFunction)>(); + + /// from: public float getDropThreshold() + /// + /// the minimum whitespace, as a multiple of the max height of the current characters beyond which the current line + /// start is considered to be a paragraph start. + ///@return the character height multiple for max allowed whitespace between lines in the same paragraph. + double getDropThreshold() { + return _getDropThreshold(reference).float; + } + + static final _setDropThreshold = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Float)>>("PDFTextStripper__setDropThreshold") + .asFunction, double)>(); + + /// from: public void setDropThreshold(float dropThresholdValue) + /// + /// sets the minimum whitespace, as a multiple of the max height of the current characters beyond which the current + /// line start is considered to be a paragraph start. The default value is 2.5. + ///@param dropThresholdValue the character height multiple for max allowed whitespace between lines in the same + /// paragraph. + void setDropThreshold( + double dropThresholdValue, + ) { + return _setDropThreshold(reference, dropThresholdValue).check(); + } + + static final _getParagraphStart = jniLookup< + ffi + .NativeFunction)>>( + "PDFTextStripper__getParagraphStart") + .asFunction)>(); + + /// from: public java.lang.String getParagraphStart() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Returns the string which will be used at the beginning of a paragraph. + ///@return the paragraph start string + jni.JString getParagraphStart() { + return const jni.JStringType() + .fromRef(_getParagraphStart(reference).object); + } + + static final _setParagraphStart = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDFTextStripper__setParagraphStart") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void setParagraphStart(java.lang.String s) + /// + /// Sets the string which will be used at the beginning of a paragraph. + ///@param s the paragraph start string + void setParagraphStart( + jni.JString s, + ) { + return _setParagraphStart(reference, s.reference).check(); + } + + static final _getParagraphEnd = jniLookup< + ffi + .NativeFunction)>>( + "PDFTextStripper__getParagraphEnd") + .asFunction)>(); + + /// from: public java.lang.String getParagraphEnd() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Returns the string which will be used at the end of a paragraph. + ///@return the paragraph end string + jni.JString getParagraphEnd() { + return const jni.JStringType().fromRef(_getParagraphEnd(reference).object); + } + + static final _setParagraphEnd = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDFTextStripper__setParagraphEnd") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void setParagraphEnd(java.lang.String s) + /// + /// Sets the string which will be used at the end of a paragraph. + ///@param s the paragraph end string + void setParagraphEnd( + jni.JString s, + ) { + return _setParagraphEnd(reference, s.reference).check(); + } + + static final _getPageStart = jniLookup< + ffi + .NativeFunction)>>( + "PDFTextStripper__getPageStart") + .asFunction)>(); + + /// from: public java.lang.String getPageStart() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Returns the string which will be used at the beginning of a page. + ///@return the page start string + jni.JString getPageStart() { + return const jni.JStringType().fromRef(_getPageStart(reference).object); + } + + static final _setPageStart = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDFTextStripper__setPageStart") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void setPageStart(java.lang.String pageStartValue) + /// + /// Sets the string which will be used at the beginning of a page. + ///@param pageStartValue the page start string + void setPageStart( + jni.JString pageStartValue, + ) { + return _setPageStart(reference, pageStartValue.reference).check(); + } + + static final _getPageEnd = jniLookup< + ffi + .NativeFunction)>>( + "PDFTextStripper__getPageEnd") + .asFunction)>(); + + /// from: public java.lang.String getPageEnd() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Returns the string which will be used at the end of a page. + ///@return the page end string + jni.JString getPageEnd() { + return const jni.JStringType().fromRef(_getPageEnd(reference).object); + } + + static final _setPageEnd = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDFTextStripper__setPageEnd") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void setPageEnd(java.lang.String pageEndValue) + /// + /// Sets the string which will be used at the end of a page. + ///@param pageEndValue the page end string + void setPageEnd( + jni.JString pageEndValue, + ) { + return _setPageEnd(reference, pageEndValue.reference).check(); + } + + static final _getArticleStart = jniLookup< + ffi + .NativeFunction)>>( + "PDFTextStripper__getArticleStart") + .asFunction)>(); + + /// from: public java.lang.String getArticleStart() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Returns the string which will be used at the beginning of an article. + ///@return the article start string + jni.JString getArticleStart() { + return const jni.JStringType().fromRef(_getArticleStart(reference).object); + } + + static final _setArticleStart = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDFTextStripper__setArticleStart") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void setArticleStart(java.lang.String articleStartValue) + /// + /// Sets the string which will be used at the beginning of an article. + ///@param articleStartValue the article start string + void setArticleStart( + jni.JString articleStartValue, + ) { + return _setArticleStart(reference, articleStartValue.reference).check(); + } + + static final _getArticleEnd = jniLookup< + ffi + .NativeFunction)>>( + "PDFTextStripper__getArticleEnd") + .asFunction)>(); + + /// from: public java.lang.String getArticleEnd() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Returns the string which will be used at the end of an article. + ///@return the article end string + jni.JString getArticleEnd() { + return const jni.JStringType().fromRef(_getArticleEnd(reference).object); + } + + static final _setArticleEnd = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDFTextStripper__setArticleEnd") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void setArticleEnd(java.lang.String articleEndValue) + /// + /// Sets the string which will be used at the end of an article. + ///@param articleEndValue the article end string + void setArticleEnd( + jni.JString articleEndValue, + ) { + return _setArticleEnd(reference, articleEndValue.reference).check(); + } + + static final _writeParagraphSeparator = jniLookup< + ffi + .NativeFunction)>>( + "PDFTextStripper__writeParagraphSeparator") + .asFunction)>(); + + /// from: protected void writeParagraphSeparator() + /// + /// writes the paragraph separator string to the output. + ///@throws IOException if something went wrong + void writeParagraphSeparator() { + return _writeParagraphSeparator(reference).check(); + } + + static final _writeParagraphStart = jniLookup< + ffi + .NativeFunction)>>( + "PDFTextStripper__writeParagraphStart") + .asFunction)>(); + + /// from: protected void writeParagraphStart() + /// + /// Write something (if defined) at the start of a paragraph. + ///@throws IOException if something went wrong + void writeParagraphStart() { + return _writeParagraphStart(reference).check(); + } + + static final _writeParagraphEnd = jniLookup< + ffi + .NativeFunction)>>( + "PDFTextStripper__writeParagraphEnd") + .asFunction)>(); + + /// from: protected void writeParagraphEnd() + /// + /// Write something (if defined) at the end of a paragraph. + ///@throws IOException if something went wrong + void writeParagraphEnd() { + return _writeParagraphEnd(reference).check(); + } + + static final _writePageStart = jniLookup< + ffi + .NativeFunction)>>( + "PDFTextStripper__writePageStart") + .asFunction)>(); + + /// from: protected void writePageStart() + /// + /// Write something (if defined) at the start of a page. + ///@throws IOException if something went wrong + void writePageStart() { + return _writePageStart(reference).check(); + } + + static final _writePageEnd = jniLookup< + ffi + .NativeFunction)>>( + "PDFTextStripper__writePageEnd") + .asFunction)>(); + + /// from: protected void writePageEnd() + /// + /// Write something (if defined) at the end of a page. + ///@throws IOException if something went wrong + void writePageEnd() { + return _writePageEnd(reference).check(); + } + + static final _setListItemPatterns = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>>( + "PDFTextStripper__setListItemPatterns") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: protected void setListItemPatterns(java.util.List patterns) + /// + /// use to supply a different set of regular expression patterns for matching list item starts. + ///@param patterns list of patterns + void setListItemPatterns( + jni.JList patterns, + ) { + return _setListItemPatterns(reference, patterns.reference).check(); + } + + static final _getListItemPatterns = jniLookup< + ffi + .NativeFunction)>>( + "PDFTextStripper__getListItemPatterns") + .asFunction)>(); + + /// from: protected java.util.List getListItemPatterns() + /// The returned object must be released after use, by calling the [release] method. + /// + /// returns a list of regular expression Patterns representing different common list item formats. For example + /// numbered items of form: + ///
    + ///
  1. some text
  2. + ///
  3. more text
  4. + ///
+ /// or + ///
    + ///
  • some text
  • + ///
  • more text
  • + ///
+ /// etc., all begin with some character pattern. The pattern "\\d+\." (matches "1.", "2.", ...) or "\[\\d+\]" + /// (matches "[1]", "[2]", ...). + /// + /// This method returns a list of such regular expression Patterns. + ///@return a list of Pattern objects. + jni.JList getListItemPatterns() { + return const jni.JListType(jni.JObjectType()) + .fromRef(_getListItemPatterns(reference).object); + } + + static final _matchPattern = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("PDFTextStripper__matchPattern") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: static protected java.util.regex.Pattern matchPattern(java.lang.String string, java.util.List patterns) + /// The returned object must be released after use, by calling the [release] method. + /// + /// iterates over the specified list of Patterns until it finds one that matches the specified string. Then returns + /// the Pattern. + /// + /// Order of the supplied list of patterns is important as most common patterns should come first. Patterns should be + /// strict in general, and all will be used with case sensitivity on. + /// + /// + ///@param string the string to be searched + ///@param patterns list of patterns + ///@return matching pattern + static jni.JObject matchPattern( + jni.JString string, + jni.JList patterns, + ) { + return const jni.JObjectType() + .fromRef(_matchPattern(string.reference, patterns.reference).object); + } +} + +final class $PDFTextStripperType extends jni.JObjType { + const $PDFTextStripperType(); + + @override + String get signature => r"Lorg/apache/pdfbox/text/PDFTextStripper;"; + + @override + PDFTextStripper fromRef(jni.JObjectPtr ref) => PDFTextStripper.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($PDFTextStripperType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($PDFTextStripperType) && + other is $PDFTextStripperType; + } +} diff --git a/pkgs/jnigen/example/pdfbox_plugin/lib/src/third_party/org/apache/pdfbox/text/_package.dart b/pkgs/jnigen/example/pdfbox_plugin/lib/src/third_party/org/apache/pdfbox/text/_package.dart new file mode 100644 index 000000000..07c57f7af --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/lib/src/third_party/org/apache/pdfbox/text/_package.dart @@ -0,0 +1 @@ +export "PDFTextStripper.dart"; diff --git a/pkgs/jnigen/example/pdfbox_plugin/linux/CMakeLists.txt b/pkgs/jnigen/example/pdfbox_plugin/linux/CMakeLists.txt new file mode 100644 index 000000000..986e388aa --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/linux/CMakeLists.txt @@ -0,0 +1,22 @@ +# The Flutter tooling requires that developers have CMake 3.10 or later +# installed. You should not increase this version, as doing so will cause +# the plugin to fail to compile for some customers of the plugin. +cmake_minimum_required(VERSION 3.10) + +# Project-level configuration. +set(PROJECT_NAME "pdfbox_plugin") +project(${PROJECT_NAME} LANGUAGES CXX) + +# Invoke the build for native code shared with the other target platforms. +# This can be changed to accomodate different builds. +add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../src" "${CMAKE_CURRENT_BINARY_DIR}/shared") + +# List of absolute paths to libraries that should be bundled with the plugin. +# This list could contain prebuilt libraries, or libraries created by an +# external build triggered from this build file. +set(pdfbox_plugin_bundled_libraries + # Defined in ../src/CMakeLists.txt. + # This can be changed to accomodate different builds. + $ + PARENT_SCOPE +) diff --git a/pkgs/jnigen/example/pdfbox_plugin/pubspec.yaml b/pkgs/jnigen/example/pdfbox_plugin/pubspec.yaml new file mode 100644 index 000000000..a269d5a6f --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/pubspec.yaml @@ -0,0 +1,38 @@ +name: pdfbox_plugin +description: | + Example of using jnigen to generate bindings for a non-trivial Java library. +version: 0.0.1 +publish_to: none +homepage: https://github.com/dart-lang/jnigen + +environment: + sdk: '>=3.1.0 <4.0.0' + #flutter: ">=2.11.0" + +dependencies: + jni: + path: ../../../jni/ + #flutter: + #sdk: flutter + plugin_platform_interface: ^2.0.2 + +dev_dependencies: + ## Path dependency for sake of the example + jnigen: + path: ../../ + test: any + lints: ^2.0.0 + +flutter: + # A JNI plugin uses FFI for calling into C code. Thus the relevant shared + # library artifacts must be bundled with final application. + # Please refer to README.md for a detailed explanation. + plugin: + platforms: + android: + ffiPlugin: true + linux: + ffiPlugin: true + windows: + ffiPlugin: true + diff --git a/pkgs/jnigen/example/pdfbox_plugin/src/CMakeLists.txt b/pkgs/jnigen/example/pdfbox_plugin/src/CMakeLists.txt new file mode 100644 index 000000000..f35376568 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/src/CMakeLists.txt @@ -0,0 +1,32 @@ +# jni_native_build (Build with jni:setup. Do not delete this line.) + +# The Flutter tooling requires that developers have CMake 3.10 or later +# installed. You should not increase this version, as doing so will cause +# the plugin to fail to compile for some customers of the plugin. +cmake_minimum_required(VERSION 3.10) + +project(pdfbox_plugin VERSION 0.0.1 LANGUAGES C) + +add_library(pdfbox_plugin SHARED + "third_party//pdfbox_plugin.c" +) + +set_target_properties(pdfbox_plugin PROPERTIES + OUTPUT_NAME "pdfbox_plugin" +) + +target_compile_definitions(pdfbox_plugin PUBLIC DART_SHARED_LIB) + +if(WIN32) + set_target_properties(${TARGET_NAME} PROPERTIES + LINK_FLAGS "/DELAYLOAD:jvm.dll") +endif() + +if (ANDROID) + target_link_libraries(pdfbox_plugin log) +else() + find_package(Java REQUIRED) + find_package(JNI REQUIRED) + include_directories(${JNI_INCLUDE_DIRS}) + target_link_libraries(pdfbox_plugin ${JNI_LIBRARIES}) +endif() diff --git a/pkgs/jnigen/example/pdfbox_plugin/src/third_party/.clang-format b/pkgs/jnigen/example/pdfbox_plugin/src/third_party/.clang-format new file mode 100644 index 000000000..a256c2f09 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/src/third_party/.clang-format @@ -0,0 +1,15 @@ +# From dart SDK: https://github.com/dart-lang/sdk/blob/main/.clang-format + +# Defines the Chromium style for automatic reformatting. +# http://clang.llvm.org/docs/ClangFormatStyleOptions.html +BasedOnStyle: Chromium + +# clang-format doesn't seem to do a good job of this for longer comments. +ReflowComments: 'false' + +# We have lots of these. Though we need to put them all in curly braces, +# clang-format can't do that. +AllowShortIfStatementsOnASingleLine: 'true' + +# Put escaped newlines into the rightmost column. +AlignEscapedNewlinesLeft: false diff --git a/pkgs/jnigen/example/pdfbox_plugin/src/third_party/dartjni.h b/pkgs/jnigen/example/pdfbox_plugin/src/third_party/dartjni.h new file mode 100644 index 000000000..8f1dc7481 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/src/third_party/dartjni.h @@ -0,0 +1,424 @@ +// 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. + +#pragma once + +// Note: include appropriate system jni.h as found by CMake, not third_party/jni.h. +#include +#include +#include +#include + +#if _WIN32 +#include +#else +#include +#include +#endif + +#if _WIN32 +#define FFI_PLUGIN_EXPORT __declspec(dllexport) +#else +#define FFI_PLUGIN_EXPORT +#endif + +#if defined _WIN32 +#define thread_local __declspec(thread) +#else +#define thread_local __thread +#endif + +#ifdef __ANDROID__ +#include +#endif + +#ifdef __ANDROID__ +#define __ENVP_CAST (JNIEnv**) +#else +#define __ENVP_CAST (void**) +#endif + +/// Locking functions for windows and pthread. + +#if defined _WIN32 +#include + +typedef CRITICAL_SECTION MutexLock; +typedef CONDITION_VARIABLE ConditionVariable; + +static inline void init_lock(MutexLock* lock) { + InitializeCriticalSection(lock); +} + +static inline void acquire_lock(MutexLock* lock) { + EnterCriticalSection(lock); +} + +static inline void release_lock(MutexLock* lock) { + LeaveCriticalSection(lock); +} + +static inline void destroy_lock(MutexLock* lock) { + DeleteCriticalSection(lock); +} + +static inline void init_cond(ConditionVariable* cond) { + InitializeConditionVariable(cond); +} + +static inline void signal_cond(ConditionVariable* cond) { + WakeConditionVariable(cond); +} + +static inline void wait_for(ConditionVariable* cond, MutexLock* lock) { + SleepConditionVariableCS(cond, lock, INFINITE); +} + +static inline void destroy_cond(ConditionVariable* cond) { + // Not available. +} + +#elif defined __APPLE__ || defined __LINUX__ || defined __ANDROID__ || \ + defined __GNUC__ +#include + +typedef pthread_mutex_t MutexLock; +typedef pthread_cond_t ConditionVariable; + +static inline void init_lock(MutexLock* lock) { + pthread_mutex_init(lock, NULL); +} + +static inline void acquire_lock(MutexLock* lock) { + pthread_mutex_lock(lock); +} + +static inline void release_lock(MutexLock* lock) { + pthread_mutex_unlock(lock); +} + +static inline void destroy_lock(MutexLock* lock) { + pthread_mutex_destroy(lock); +} + +static inline void init_cond(ConditionVariable* cond) { + pthread_cond_init(cond, NULL); +} + +static inline void signal_cond(ConditionVariable* cond) { + pthread_cond_signal(cond); +} + +static inline void wait_for(ConditionVariable* cond, MutexLock* lock) { + pthread_cond_wait(cond, lock); +} + +static inline void destroy_cond(ConditionVariable* cond) { + pthread_cond_destroy(cond); +} + +#else + +#error "No locking/condition variable support; Possibly unsupported platform" + +#endif + +typedef struct CallbackResult { + MutexLock lock; + ConditionVariable cond; + int ready; + jobject object; +} CallbackResult; + +typedef struct JniLocks { + MutexLock classLoadingLock; + MutexLock methodLoadingLock; + MutexLock fieldLoadingLock; +} JniLocks; + +/// Represents the error when dart-jni layer has already spawned singleton VM. +#define DART_JNI_SINGLETON_EXISTS (-99); + +/// Stores the global state of the JNI. +typedef struct JniContext { + JavaVM* jvm; + jobject classLoader; + jmethodID loadClassMethod; + jobject currentActivity; + jobject appContext; + JniLocks locks; +} JniContext; + +// jniEnv for this thread, used by inline functions in this header, +// therefore declared as extern. +extern thread_local JNIEnv* jniEnv; + +extern JniContext* jni; + +/// Types used by JNI API to distinguish between primitive types. +enum JniType { + booleanType = 0, + byteType = 1, + shortType = 2, + charType = 3, + intType = 4, + longType = 5, + floatType = 6, + doubleType = 7, + objectType = 8, + voidType = 9, +}; + +/// Result type for use by JNI. +/// +/// If [exception] is null, it means the result is valid. +/// It's assumed that the caller knows the expected type in [result]. +typedef struct JniResult { + jvalue value; + jthrowable exception; +} JniResult; + +/// Similar to [JniResult] but for class lookups. +typedef struct JniClassLookupResult { + jclass value; + jthrowable exception; +} JniClassLookupResult; + +/// Similar to [JniResult] but for method/field ID lookups. +typedef struct JniPointerResult { + const void* value; + jthrowable exception; +} JniPointerResult; + +/// JniExceptionDetails holds 2 jstring objects, one is the result of +/// calling `toString` on exception object, other is stack trace; +typedef struct JniExceptionDetails { + jstring message; + jstring stacktrace; +} JniExceptionDetails; + +/// This struct contains functions which wrap method call / field access conveniently along with +/// exception checking. +/// +/// Flutter embedding checks for pending JNI exceptions before an FFI transition, which requires us +/// to check for and clear the exception before returning to dart code, which requires these functions +/// to return result types. +typedef struct JniAccessorsStruct { + JniClassLookupResult (*getClass)(char* internalName); + JniPointerResult (*getFieldID)(jclass cls, char* fieldName, char* signature); + JniPointerResult (*getStaticFieldID)(jclass cls, + char* fieldName, + char* signature); + JniPointerResult (*getMethodID)(jclass cls, + char* methodName, + char* signature); + JniPointerResult (*getStaticMethodID)(jclass cls, + char* methodName, + char* signature); + JniResult (*newObject)(jclass cls, jmethodID ctor, jvalue* args); + JniResult (*newPrimitiveArray)(jsize length, int type); + JniResult (*newObjectArray)(jsize length, + jclass elementClass, + jobject initialElement); + JniResult (*getArrayElement)(jarray array, int index, int type); + JniResult (*callMethod)(jobject obj, + jmethodID methodID, + int callType, + jvalue* args); + JniResult (*callStaticMethod)(jclass cls, + jmethodID methodID, + int callType, + jvalue* args); + JniResult (*getField)(jobject obj, jfieldID fieldID, int callType); + JniResult (*getStaticField)(jclass cls, jfieldID fieldID, int callType); + JniExceptionDetails (*getExceptionDetails)(jthrowable exception); +} JniAccessorsStruct; + +FFI_PLUGIN_EXPORT JniAccessorsStruct* GetAccessors(); + +FFI_PLUGIN_EXPORT JavaVM* GetJavaVM(void); + +FFI_PLUGIN_EXPORT JNIEnv* GetJniEnv(void); + +/// Spawn a JVM with given arguments. +/// +/// Returns JNI_OK on success, and one of the documented JNI error codes on +/// failure. It returns DART_JNI_SINGLETON_EXISTS if an attempt to spawn multiple +/// JVMs is made, even if the underlying API potentially supports multiple VMs. +FFI_PLUGIN_EXPORT int SpawnJvm(JavaVMInitArgs* args); + +/// Load class through platform-specific mechanism. +/// +/// Currently uses application classloader on android, +/// and JNIEnv->FindClass on other platforms. +FFI_PLUGIN_EXPORT jclass FindClass(const char* name); + +/// Returns Application classLoader (on Android), +/// which can be used to load application and platform classes. +/// +/// On other platforms, NULL is returned. +FFI_PLUGIN_EXPORT jobject GetClassLoader(void); + +/// Returns application context on Android. +/// +/// On other platforms, NULL is returned. +FFI_PLUGIN_EXPORT jobject GetApplicationContext(void); + +/// Returns current activity of the app on Android. +FFI_PLUGIN_EXPORT jobject GetCurrentActivity(void); + +static inline void attach_thread() { + if (jniEnv == NULL) { + (*jni->jvm)->AttachCurrentThread(jni->jvm, __ENVP_CAST & jniEnv, NULL); + } +} + +/// Load class into [cls] using platform specific mechanism +static inline void load_class_platform(jclass* cls, const char* name) { +#ifdef __ANDROID__ + jstring className = (*jniEnv)->NewStringUTF(jniEnv, name); + *cls = (*jniEnv)->CallObjectMethod(jniEnv, jni->classLoader, + jni->loadClassMethod, className); + (*jniEnv)->DeleteLocalRef(jniEnv, className); +#else + *cls = (*jniEnv)->FindClass(jniEnv, name); +#endif +} + +static inline void load_class_local_ref(jclass* cls, const char* name) { + if (*cls == NULL) { + acquire_lock(&jni->locks.classLoadingLock); + if (*cls == NULL) { + load_class_platform(cls, name); + } + release_lock(&jni->locks.classLoadingLock); + } +} + +static inline void load_class_global_ref(jclass* cls, const char* name) { + if (*cls == NULL) { + jclass tmp = NULL; + acquire_lock(&jni->locks.classLoadingLock); + if (*cls == NULL) { + load_class_platform(&tmp, name); + if (!(*jniEnv)->ExceptionCheck(jniEnv)) { + *cls = (*jniEnv)->NewGlobalRef(jniEnv, tmp); + (*jniEnv)->DeleteLocalRef(jniEnv, tmp); + } + } + release_lock(&jni->locks.classLoadingLock); + } +} + +static inline void load_method(jclass cls, + jmethodID* res, + const char* name, + const char* sig) { + if (*res == NULL) { + acquire_lock(&jni->locks.methodLoadingLock); + if (*res == NULL) { + *res = (*jniEnv)->GetMethodID(jniEnv, cls, name, sig); + } + release_lock(&jni->locks.methodLoadingLock); + } +} + +static inline void load_static_method(jclass cls, + jmethodID* res, + const char* name, + const char* sig) { + if (*res == NULL) { + acquire_lock(&jni->locks.methodLoadingLock); + if (*res == NULL) { + *res = (*jniEnv)->GetStaticMethodID(jniEnv, cls, name, sig); + } + release_lock(&jni->locks.methodLoadingLock); + } +} + +static inline void load_field(jclass cls, + jfieldID* res, + const char* name, + const char* sig) { + if (*res == NULL) { + acquire_lock(&jni->locks.fieldLoadingLock); + if (*res == NULL) { + *res = (*jniEnv)->GetFieldID(jniEnv, cls, name, sig); + } + release_lock(&jni->locks.fieldLoadingLock); + } +} + +static inline void load_static_field(jclass cls, + jfieldID* res, + const char* name, + const char* sig) { + if (*res == NULL) { + acquire_lock(&jni->locks.fieldLoadingLock); + if (*res == NULL) { + *res = (*jniEnv)->GetStaticFieldID(jniEnv, cls, name, sig); + } + release_lock(&jni->locks.fieldLoadingLock); + } +} + +static inline jobject to_global_ref(jobject ref) { + jobject g = (*jniEnv)->NewGlobalRef(jniEnv, ref); + (*jniEnv)->DeleteLocalRef(jniEnv, ref); + return g; +} + +// These functions are useful for C+Dart bindings, and not required for pure dart bindings. + +FFI_PLUGIN_EXPORT JniContext* GetJniContextPtr(); + +/// For use by jni_gen's generated code +/// don't use these. + +// these 2 fn ptr vars will be defined by generated code library +extern JniContext* (*context_getter)(void); +extern JNIEnv* (*env_getter)(void); + +// this function will be exported by generated code library +// it will set above 2 variables. +FFI_PLUGIN_EXPORT void setJniGetters(struct JniContext* (*cg)(void), + JNIEnv* (*eg)(void)); + +static inline void load_env() { + if (jniEnv == NULL) { + jni = context_getter(); + jniEnv = env_getter(); + } +} + +static inline jthrowable check_exception() { + jthrowable exception = (*jniEnv)->ExceptionOccurred(jniEnv); + if (exception != NULL) (*jniEnv)->ExceptionClear(jniEnv); + if (exception == NULL) return NULL; + return to_global_ref(exception); +} + +static inline JniResult to_global_ref_result(jobject ref) { + JniResult result; + result.exception = check_exception(); + if (result.exception == NULL) { + result.value.l = to_global_ref(ref); + } + return result; +} + +FFI_PLUGIN_EXPORT intptr_t InitDartApiDL(void* data); + +FFI_PLUGIN_EXPORT +JniResult DartException__ctor(jstring message); + +FFI_PLUGIN_EXPORT +JniResult PortContinuation__ctor(int64_t j); + +FFI_PLUGIN_EXPORT +JniResult PortProxy__newInstance(jobject binaryName, + int64_t port, + int64_t functionPtr); + +FFI_PLUGIN_EXPORT void resultFor(CallbackResult* result, jobject object); diff --git a/pkgs/jnigen/example/pdfbox_plugin/src/third_party/pdfbox_plugin.c b/pkgs/jnigen/example/pdfbox_plugin/src/third_party/pdfbox_plugin.c new file mode 100644 index 000000000..6b111335c --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/src/third_party/pdfbox_plugin.c @@ -0,0 +1,2872 @@ +// Generated from Apache PDFBox library which is licensed under the Apache License 2.0. +// The following copyright from the original authors applies. +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Autogenerated by jnigen. DO NOT EDIT! + +#include +#include "dartjni.h" +#include "jni.h" + +thread_local JNIEnv* jniEnv; +JniContext* jni; + +JniContext* (*context_getter)(void); +JNIEnv* (*env_getter)(void); + +void setJniGetters(JniContext* (*cg)(void), JNIEnv* (*eg)(void)) { + context_getter = cg; + env_getter = eg; +} + +// org.apache.pdfbox.pdmodel.PDDocument +jclass _c_PDDocument = NULL; + +jmethodID _m_PDDocument__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__new0() { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__new0, "", "()V"); + if (_m_PDDocument__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->NewObject(jniEnv, _c_PDDocument, _m_PDDocument__new0); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocument__new1 = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__new1(jobject memUsageSetting) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__new1, "", + "(Lorg/apache/pdfbox/io/MemoryUsageSetting;)V"); + if (_m_PDDocument__new1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject(jniEnv, _c_PDDocument, + _m_PDDocument__new1, memUsageSetting); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocument__new2 = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__new2(jobject doc) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__new2, "", + "(Lorg/apache/pdfbox/cos/COSDocument;)V"); + if (_m_PDDocument__new2 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->NewObject(jniEnv, _c_PDDocument, _m_PDDocument__new2, doc); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocument__new3 = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__new3(jobject doc, jobject source) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__new3, "", + "(Lorg/apache/pdfbox/cos/COSDocument;Lorg/apache/pdfbox/io/" + "RandomAccessRead;)V"); + if (_m_PDDocument__new3 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject(jniEnv, _c_PDDocument, + _m_PDDocument__new3, doc, source); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocument__new4 = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__new4(jobject doc, jobject source, jobject permission) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__new4, "", + "(Lorg/apache/pdfbox/cos/COSDocument;Lorg/apache/pdfbox/io/" + "RandomAccessRead;Lorg/apache/pdfbox/pdmodel/encryption/" + "AccessPermission;)V"); + if (_m_PDDocument__new4 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject( + jniEnv, _c_PDDocument, _m_PDDocument__new4, doc, source, permission); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocument__addPage = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__addPage(jobject self_, jobject page) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__addPage, "addPage", + "(Lorg/apache/pdfbox/pdmodel/PDPage;)V"); + if (_m_PDDocument__addPage == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDDocument__addPage, page); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDDocument__addSignature = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__addSignature(jobject self_, jobject sigObject) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__addSignature, "addSignature", + "(Lorg/apache/pdfbox/pdmodel/interactive/digitalsignature/" + "PDSignature;)V"); + if (_m_PDDocument__addSignature == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDDocument__addSignature, + sigObject); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDDocument__addSignature1 = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__addSignature1(jobject self_, + jobject sigObject, + jobject options) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__addSignature1, "addSignature", + "(Lorg/apache/pdfbox/pdmodel/interactive/digitalsignature/" + "PDSignature;Lorg/apache/pdfbox/pdmodel/interactive/" + "digitalsignature/SignatureOptions;)V"); + if (_m_PDDocument__addSignature1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDDocument__addSignature1, + sigObject, options); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDDocument__addSignature2 = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__addSignature2(jobject self_, + jobject sigObject, + jobject signatureInterface) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__addSignature2, "addSignature", + "(Lorg/apache/pdfbox/pdmodel/interactive/digitalsignature/" + "PDSignature;Lorg/apache/pdfbox/pdmodel/interactive/" + "digitalsignature/SignatureInterface;)V"); + if (_m_PDDocument__addSignature2 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDDocument__addSignature2, + sigObject, signatureInterface); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDDocument__addSignature3 = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__addSignature3(jobject self_, + jobject sigObject, + jobject signatureInterface, + jobject options) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__addSignature3, "addSignature", + "(Lorg/apache/pdfbox/pdmodel/interactive/digitalsignature/" + "PDSignature;Lorg/apache/pdfbox/pdmodel/interactive/" + "digitalsignature/SignatureInterface;Lorg/apache/pdfbox/pdmodel/" + "interactive/digitalsignature/SignatureOptions;)V"); + if (_m_PDDocument__addSignature3 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDDocument__addSignature3, + sigObject, signatureInterface, options); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDDocument__addSignatureField = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__addSignatureField(jobject self_, + jobject sigFields, + jobject signatureInterface, + jobject options) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__addSignatureField, + "addSignatureField", + "(Ljava/util/List;Lorg/apache/pdfbox/pdmodel/interactive/" + "digitalsignature/SignatureInterface;Lorg/apache/pdfbox/pdmodel/" + "interactive/digitalsignature/SignatureOptions;)V"); + if (_m_PDDocument__addSignatureField == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDDocument__addSignatureField, + sigFields, signatureInterface, options); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDDocument__removePage = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__removePage(jobject self_, jobject page) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__removePage, "removePage", + "(Lorg/apache/pdfbox/pdmodel/PDPage;)V"); + if (_m_PDDocument__removePage == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDDocument__removePage, page); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDDocument__removePage1 = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__removePage1(jobject self_, int32_t pageNumber) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__removePage1, "removePage", "(I)V"); + if (_m_PDDocument__removePage1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDDocument__removePage1, + pageNumber); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDDocument__importPage = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__importPage(jobject self_, jobject page) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method( + _c_PDDocument, &_m_PDDocument__importPage, "importPage", + "(Lorg/apache/pdfbox/pdmodel/PDPage;)Lorg/apache/pdfbox/pdmodel/PDPage;"); + if (_m_PDDocument__importPage == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_PDDocument__importPage, page); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocument__getDocument = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__getDocument(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__getDocument, "getDocument", + "()Lorg/apache/pdfbox/cos/COSDocument;"); + if (_m_PDDocument__getDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_PDDocument__getDocument); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocument__getDocumentInformation = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__getDocumentInformation(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__getDocumentInformation, + "getDocumentInformation", + "()Lorg/apache/pdfbox/pdmodel/PDDocumentInformation;"); + if (_m_PDDocument__getDocumentInformation == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_PDDocument__getDocumentInformation); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocument__setDocumentInformation = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__setDocumentInformation(jobject self_, jobject info) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__setDocumentInformation, + "setDocumentInformation", + "(Lorg/apache/pdfbox/pdmodel/PDDocumentInformation;)V"); + if (_m_PDDocument__setDocumentInformation == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, + _m_PDDocument__setDocumentInformation, info); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDDocument__getDocumentCatalog = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__getDocumentCatalog(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__getDocumentCatalog, + "getDocumentCatalog", + "()Lorg/apache/pdfbox/pdmodel/PDDocumentCatalog;"); + if (_m_PDDocument__getDocumentCatalog == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_PDDocument__getDocumentCatalog); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocument__isEncrypted = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__isEncrypted(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__isEncrypted, "isEncrypted", "()Z"); + if (_m_PDDocument__isEncrypted == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = + (*jniEnv)->CallBooleanMethod(jniEnv, self_, _m_PDDocument__isEncrypted); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_PDDocument__getEncryption = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__getEncryption(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__getEncryption, "getEncryption", + "()Lorg/apache/pdfbox/pdmodel/encryption/PDEncryption;"); + if (_m_PDDocument__getEncryption == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_PDDocument__getEncryption); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocument__setEncryptionDictionary = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__setEncryptionDictionary(jobject self_, + jobject encryption) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__setEncryptionDictionary, + "setEncryptionDictionary", + "(Lorg/apache/pdfbox/pdmodel/encryption/PDEncryption;)V"); + if (_m_PDDocument__setEncryptionDictionary == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, + _m_PDDocument__setEncryptionDictionary, encryption); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDDocument__getLastSignatureDictionary = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__getLastSignatureDictionary(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method( + _c_PDDocument, &_m_PDDocument__getLastSignatureDictionary, + "getLastSignatureDictionary", + "()Lorg/apache/pdfbox/pdmodel/interactive/digitalsignature/PDSignature;"); + if (_m_PDDocument__getLastSignatureDictionary == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_PDDocument__getLastSignatureDictionary); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocument__getSignatureFields = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__getSignatureFields(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__getSignatureFields, + "getSignatureFields", "()Ljava/util/List;"); + if (_m_PDDocument__getSignatureFields == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_PDDocument__getSignatureFields); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocument__getSignatureDictionaries = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__getSignatureDictionaries(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__getSignatureDictionaries, + "getSignatureDictionaries", "()Ljava/util/List;"); + if (_m_PDDocument__getSignatureDictionaries == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_PDDocument__getSignatureDictionaries); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocument__registerTrueTypeFontForClosing = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__registerTrueTypeFontForClosing(jobject self_, + jobject ttf) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__registerTrueTypeFontForClosing, + "registerTrueTypeFontForClosing", + "(Lorg/apache/fontbox/ttf/TrueTypeFont;)V"); + if (_m_PDDocument__registerTrueTypeFontForClosing == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, + _m_PDDocument__registerTrueTypeFontForClosing, ttf); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDDocument__load = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__load(jobject file) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_PDDocument, &_m_PDDocument__load, "load", + "(Ljava/io/File;)Lorg/apache/pdfbox/pdmodel/PDDocument;"); + if (_m_PDDocument__load == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_PDDocument, _m_PDDocument__load, file); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocument__load1 = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__load1(jobject file, jobject memUsageSetting) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method( + _c_PDDocument, &_m_PDDocument__load1, "load", + "(Ljava/io/File;Lorg/apache/pdfbox/io/MemoryUsageSetting;)Lorg/apache/" + "pdfbox/pdmodel/PDDocument;"); + if (_m_PDDocument__load1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_PDDocument, _m_PDDocument__load1, file, memUsageSetting); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocument__load2 = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__load2(jobject file, jobject password) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_PDDocument, &_m_PDDocument__load2, "load", + "(Ljava/io/File;Ljava/lang/String;)Lorg/apache/pdfbox/" + "pdmodel/PDDocument;"); + if (_m_PDDocument__load2 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_PDDocument, _m_PDDocument__load2, file, password); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocument__load3 = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__load3(jobject file, + jobject password, + jobject memUsageSetting) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method( + _c_PDDocument, &_m_PDDocument__load3, "load", + "(Ljava/io/File;Ljava/lang/String;Lorg/apache/pdfbox/io/" + "MemoryUsageSetting;)Lorg/apache/pdfbox/pdmodel/PDDocument;"); + if (_m_PDDocument__load3 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_PDDocument, _m_PDDocument__load3, file, password, + memUsageSetting); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocument__load4 = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__load4(jobject file, + jobject password, + jobject keyStore, + jobject alias) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method( + _c_PDDocument, &_m_PDDocument__load4, "load", + "(Ljava/io/File;Ljava/lang/String;Ljava/io/InputStream;Ljava/lang/" + "String;)Lorg/apache/pdfbox/pdmodel/PDDocument;"); + if (_m_PDDocument__load4 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_PDDocument, _m_PDDocument__load4, file, password, keyStore, + alias); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocument__load5 = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__load5(jobject file, + jobject password, + jobject keyStore, + jobject alias, + jobject memUsageSetting) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method( + _c_PDDocument, &_m_PDDocument__load5, "load", + "(Ljava/io/File;Ljava/lang/String;Ljava/io/InputStream;Ljava/lang/" + "String;Lorg/apache/pdfbox/io/MemoryUsageSetting;)Lorg/apache/pdfbox/" + "pdmodel/PDDocument;"); + if (_m_PDDocument__load5 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_PDDocument, _m_PDDocument__load5, file, password, keyStore, + alias, memUsageSetting); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocument__load6 = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__load6(jobject input) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method( + _c_PDDocument, &_m_PDDocument__load6, "load", + "(Ljava/io/InputStream;)Lorg/apache/pdfbox/pdmodel/PDDocument;"); + if (_m_PDDocument__load6 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_PDDocument, _m_PDDocument__load6, input); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocument__load7 = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__load7(jobject input, jobject memUsageSetting) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method( + _c_PDDocument, &_m_PDDocument__load7, "load", + "(Ljava/io/InputStream;Lorg/apache/pdfbox/io/MemoryUsageSetting;)Lorg/" + "apache/pdfbox/pdmodel/PDDocument;"); + if (_m_PDDocument__load7 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_PDDocument, _m_PDDocument__load7, input, memUsageSetting); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocument__load8 = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__load8(jobject input, jobject password) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_PDDocument, &_m_PDDocument__load8, "load", + "(Ljava/io/InputStream;Ljava/lang/String;)Lorg/apache/" + "pdfbox/pdmodel/PDDocument;"); + if (_m_PDDocument__load8 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_PDDocument, _m_PDDocument__load8, input, password); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocument__load9 = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__load9(jobject input, + jobject password, + jobject keyStore, + jobject alias) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method( + _c_PDDocument, &_m_PDDocument__load9, "load", + "(Ljava/io/InputStream;Ljava/lang/String;Ljava/io/InputStream;Ljava/lang/" + "String;)Lorg/apache/pdfbox/pdmodel/PDDocument;"); + if (_m_PDDocument__load9 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_PDDocument, _m_PDDocument__load9, input, password, keyStore, + alias); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocument__load10 = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__load10(jobject input, + jobject password, + jobject memUsageSetting) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method( + _c_PDDocument, &_m_PDDocument__load10, "load", + "(Ljava/io/InputStream;Ljava/lang/String;Lorg/apache/pdfbox/io/" + "MemoryUsageSetting;)Lorg/apache/pdfbox/pdmodel/PDDocument;"); + if (_m_PDDocument__load10 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_PDDocument, _m_PDDocument__load10, input, password, + memUsageSetting); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocument__load11 = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__load11(jobject input, + jobject password, + jobject keyStore, + jobject alias, + jobject memUsageSetting) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method( + _c_PDDocument, &_m_PDDocument__load11, "load", + "(Ljava/io/InputStream;Ljava/lang/String;Ljava/io/InputStream;Ljava/lang/" + "String;Lorg/apache/pdfbox/io/MemoryUsageSetting;)Lorg/apache/pdfbox/" + "pdmodel/PDDocument;"); + if (_m_PDDocument__load11 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_PDDocument, _m_PDDocument__load11, input, password, keyStore, + alias, memUsageSetting); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocument__load12 = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__load12(jobject input) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_PDDocument, &_m_PDDocument__load12, "load", + "([B)Lorg/apache/pdfbox/pdmodel/PDDocument;"); + if (_m_PDDocument__load12 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_PDDocument, _m_PDDocument__load12, input); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocument__load13 = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__load13(jobject input, jobject password) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method( + _c_PDDocument, &_m_PDDocument__load13, "load", + "([BLjava/lang/String;)Lorg/apache/pdfbox/pdmodel/PDDocument;"); + if (_m_PDDocument__load13 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_PDDocument, _m_PDDocument__load13, input, password); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocument__load14 = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__load14(jobject input, + jobject password, + jobject keyStore, + jobject alias) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_PDDocument, &_m_PDDocument__load14, "load", + "([BLjava/lang/String;Ljava/io/InputStream;Ljava/lang/" + "String;)Lorg/apache/pdfbox/pdmodel/PDDocument;"); + if (_m_PDDocument__load14 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_PDDocument, _m_PDDocument__load14, input, password, keyStore, + alias); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocument__load15 = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__load15(jobject input, + jobject password, + jobject keyStore, + jobject alias, + jobject memUsageSetting) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method( + _c_PDDocument, &_m_PDDocument__load15, "load", + "([BLjava/lang/String;Ljava/io/InputStream;Ljava/lang/String;Lorg/apache/" + "pdfbox/io/MemoryUsageSetting;)Lorg/apache/pdfbox/pdmodel/PDDocument;"); + if (_m_PDDocument__load15 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_PDDocument, _m_PDDocument__load15, input, password, keyStore, + alias, memUsageSetting); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocument__save = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__save(jobject self_, jobject fileName) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__save, "save", + "(Ljava/lang/String;)V"); + if (_m_PDDocument__save == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDDocument__save, fileName); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDDocument__save1 = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__save1(jobject self_, jobject file) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__save1, "save", + "(Ljava/io/File;)V"); + if (_m_PDDocument__save1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDDocument__save1, file); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDDocument__save2 = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__save2(jobject self_, jobject output) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__save2, "save", + "(Ljava/io/OutputStream;)V"); + if (_m_PDDocument__save2 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDDocument__save2, output); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDDocument__saveIncremental = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__saveIncremental(jobject self_, jobject output) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__saveIncremental, "saveIncremental", + "(Ljava/io/OutputStream;)V"); + if (_m_PDDocument__saveIncremental == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDDocument__saveIncremental, + output); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDDocument__saveIncremental1 = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__saveIncremental1(jobject self_, + jobject output, + jobject objectsToWrite) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__saveIncremental1, + "saveIncremental", "(Ljava/io/OutputStream;Ljava/util/Set;)V"); + if (_m_PDDocument__saveIncremental1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDDocument__saveIncremental1, + output, objectsToWrite); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDDocument__saveIncrementalForExternalSigning = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__saveIncrementalForExternalSigning(jobject self_, + jobject output) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__saveIncrementalForExternalSigning, + "saveIncrementalForExternalSigning", + "(Ljava/io/OutputStream;)Lorg/apache/pdfbox/pdmodel/interactive/" + "digitalsignature/ExternalSigningSupport;"); + if (_m_PDDocument__saveIncrementalForExternalSigning == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_PDDocument__saveIncrementalForExternalSigning, output); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocument__getPage = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__getPage(jobject self_, int32_t pageIndex) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__getPage, "getPage", + "(I)Lorg/apache/pdfbox/pdmodel/PDPage;"); + if (_m_PDDocument__getPage == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_PDDocument__getPage, pageIndex); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocument__getPages = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__getPages(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__getPages, "getPages", + "()Lorg/apache/pdfbox/pdmodel/PDPageTree;"); + if (_m_PDDocument__getPages == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_PDDocument__getPages); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocument__getNumberOfPages = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__getNumberOfPages(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__getNumberOfPages, + "getNumberOfPages", "()I"); + if (_m_PDDocument__getNumberOfPages == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = + (*jniEnv)->CallIntMethod(jniEnv, self_, _m_PDDocument__getNumberOfPages); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_PDDocument__close = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__close(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__close, "close", "()V"); + if (_m_PDDocument__close == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDDocument__close); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDDocument__protect = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__protect(jobject self_, jobject policy) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__protect, "protect", + "(Lorg/apache/pdfbox/pdmodel/encryption/ProtectionPolicy;)V"); + if (_m_PDDocument__protect == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDDocument__protect, policy); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDDocument__getCurrentAccessPermission = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__getCurrentAccessPermission(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__getCurrentAccessPermission, + "getCurrentAccessPermission", + "()Lorg/apache/pdfbox/pdmodel/encryption/AccessPermission;"); + if (_m_PDDocument__getCurrentAccessPermission == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_PDDocument__getCurrentAccessPermission); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocument__isAllSecurityToBeRemoved = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__isAllSecurityToBeRemoved(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__isAllSecurityToBeRemoved, + "isAllSecurityToBeRemoved", "()Z"); + if (_m_PDDocument__isAllSecurityToBeRemoved == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod( + jniEnv, self_, _m_PDDocument__isAllSecurityToBeRemoved); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_PDDocument__setAllSecurityToBeRemoved = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__setAllSecurityToBeRemoved(jobject self_, + uint8_t removeAllSecurity) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__setAllSecurityToBeRemoved, + "setAllSecurityToBeRemoved", "(Z)V"); + if (_m_PDDocument__setAllSecurityToBeRemoved == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, + _m_PDDocument__setAllSecurityToBeRemoved, + removeAllSecurity); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDDocument__getDocumentId = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__getDocumentId(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__getDocumentId, "getDocumentId", + "()Ljava/lang/Long;"); + if (_m_PDDocument__getDocumentId == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_PDDocument__getDocumentId); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocument__setDocumentId = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__setDocumentId(jobject self_, jobject docId) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__setDocumentId, "setDocumentId", + "(Ljava/lang/Long;)V"); + if (_m_PDDocument__setDocumentId == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDDocument__setDocumentId, docId); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDDocument__getVersion = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__getVersion(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__getVersion, "getVersion", "()F"); + if (_m_PDDocument__getVersion == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + float _result = + (*jniEnv)->CallFloatMethod(jniEnv, self_, _m_PDDocument__getVersion); + return (JniResult){.value = {.f = _result}, .exception = check_exception()}; +} + +jmethodID _m_PDDocument__setVersion = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__setVersion(jobject self_, float newVersion) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__setVersion, "setVersion", "(F)V"); + if (_m_PDDocument__setVersion == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDDocument__setVersion, + newVersion); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDDocument__getResourceCache = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__getResourceCache(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__getResourceCache, + "getResourceCache", + "()Lorg/apache/pdfbox/pdmodel/ResourceCache;"); + if (_m_PDDocument__getResourceCache == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_PDDocument__getResourceCache); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocument__setResourceCache = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocument__setResourceCache(jobject self_, jobject resourceCache) { + load_env(); + load_class_global_ref(&_c_PDDocument, "org/apache/pdfbox/pdmodel/PDDocument"); + if (_c_PDDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocument, &_m_PDDocument__setResourceCache, + "setResourceCache", + "(Lorg/apache/pdfbox/pdmodel/ResourceCache;)V"); + if (_m_PDDocument__setResourceCache == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDDocument__setResourceCache, + resourceCache); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +// org.apache.pdfbox.pdmodel.PDDocumentInformation +jclass _c_PDDocumentInformation = NULL; + +jmethodID _m_PDDocumentInformation__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocumentInformation__new0() { + load_env(); + load_class_global_ref(&_c_PDDocumentInformation, + "org/apache/pdfbox/pdmodel/PDDocumentInformation"); + if (_c_PDDocumentInformation == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocumentInformation, &_m_PDDocumentInformation__new0, + "", "()V"); + if (_m_PDDocumentInformation__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject(jniEnv, _c_PDDocumentInformation, + _m_PDDocumentInformation__new0); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocumentInformation__new1 = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocumentInformation__new1(jobject dic) { + load_env(); + load_class_global_ref(&_c_PDDocumentInformation, + "org/apache/pdfbox/pdmodel/PDDocumentInformation"); + if (_c_PDDocumentInformation == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocumentInformation, &_m_PDDocumentInformation__new1, + "", "(Lorg/apache/pdfbox/cos/COSDictionary;)V"); + if (_m_PDDocumentInformation__new1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject(jniEnv, _c_PDDocumentInformation, + _m_PDDocumentInformation__new1, dic); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocumentInformation__getCOSObject = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocumentInformation__getCOSObject(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDDocumentInformation, + "org/apache/pdfbox/pdmodel/PDDocumentInformation"); + if (_c_PDDocumentInformation == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocumentInformation, &_m_PDDocumentInformation__getCOSObject, + "getCOSObject", "()Lorg/apache/pdfbox/cos/COSDictionary;"); + if (_m_PDDocumentInformation__getCOSObject == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_PDDocumentInformation__getCOSObject); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocumentInformation__getPropertyStringValue = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocumentInformation__getPropertyStringValue(jobject self_, + jobject propertyKey) { + load_env(); + load_class_global_ref(&_c_PDDocumentInformation, + "org/apache/pdfbox/pdmodel/PDDocumentInformation"); + if (_c_PDDocumentInformation == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocumentInformation, + &_m_PDDocumentInformation__getPropertyStringValue, + "getPropertyStringValue", + "(Ljava/lang/String;)Ljava/lang/Object;"); + if (_m_PDDocumentInformation__getPropertyStringValue == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_PDDocumentInformation__getPropertyStringValue, + propertyKey); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocumentInformation__getTitle = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocumentInformation__getTitle(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDDocumentInformation, + "org/apache/pdfbox/pdmodel/PDDocumentInformation"); + if (_c_PDDocumentInformation == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocumentInformation, &_m_PDDocumentInformation__getTitle, + "getTitle", "()Ljava/lang/String;"); + if (_m_PDDocumentInformation__getTitle == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_PDDocumentInformation__getTitle); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocumentInformation__setTitle = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocumentInformation__setTitle(jobject self_, jobject title) { + load_env(); + load_class_global_ref(&_c_PDDocumentInformation, + "org/apache/pdfbox/pdmodel/PDDocumentInformation"); + if (_c_PDDocumentInformation == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocumentInformation, &_m_PDDocumentInformation__setTitle, + "setTitle", "(Ljava/lang/String;)V"); + if (_m_PDDocumentInformation__setTitle == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDDocumentInformation__setTitle, + title); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDDocumentInformation__getAuthor = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocumentInformation__getAuthor(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDDocumentInformation, + "org/apache/pdfbox/pdmodel/PDDocumentInformation"); + if (_c_PDDocumentInformation == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocumentInformation, &_m_PDDocumentInformation__getAuthor, + "getAuthor", "()Ljava/lang/String;"); + if (_m_PDDocumentInformation__getAuthor == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_PDDocumentInformation__getAuthor); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocumentInformation__setAuthor = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocumentInformation__setAuthor(jobject self_, jobject author) { + load_env(); + load_class_global_ref(&_c_PDDocumentInformation, + "org/apache/pdfbox/pdmodel/PDDocumentInformation"); + if (_c_PDDocumentInformation == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocumentInformation, &_m_PDDocumentInformation__setAuthor, + "setAuthor", "(Ljava/lang/String;)V"); + if (_m_PDDocumentInformation__setAuthor == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDDocumentInformation__setAuthor, + author); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDDocumentInformation__getSubject = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocumentInformation__getSubject(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDDocumentInformation, + "org/apache/pdfbox/pdmodel/PDDocumentInformation"); + if (_c_PDDocumentInformation == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocumentInformation, &_m_PDDocumentInformation__getSubject, + "getSubject", "()Ljava/lang/String;"); + if (_m_PDDocumentInformation__getSubject == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_PDDocumentInformation__getSubject); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocumentInformation__setSubject = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocumentInformation__setSubject(jobject self_, jobject subject) { + load_env(); + load_class_global_ref(&_c_PDDocumentInformation, + "org/apache/pdfbox/pdmodel/PDDocumentInformation"); + if (_c_PDDocumentInformation == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocumentInformation, &_m_PDDocumentInformation__setSubject, + "setSubject", "(Ljava/lang/String;)V"); + if (_m_PDDocumentInformation__setSubject == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDDocumentInformation__setSubject, + subject); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDDocumentInformation__getKeywords = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocumentInformation__getKeywords(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDDocumentInformation, + "org/apache/pdfbox/pdmodel/PDDocumentInformation"); + if (_c_PDDocumentInformation == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocumentInformation, &_m_PDDocumentInformation__getKeywords, + "getKeywords", "()Ljava/lang/String;"); + if (_m_PDDocumentInformation__getKeywords == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_PDDocumentInformation__getKeywords); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocumentInformation__setKeywords = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocumentInformation__setKeywords(jobject self_, jobject keywords) { + load_env(); + load_class_global_ref(&_c_PDDocumentInformation, + "org/apache/pdfbox/pdmodel/PDDocumentInformation"); + if (_c_PDDocumentInformation == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocumentInformation, &_m_PDDocumentInformation__setKeywords, + "setKeywords", "(Ljava/lang/String;)V"); + if (_m_PDDocumentInformation__setKeywords == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, + _m_PDDocumentInformation__setKeywords, keywords); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDDocumentInformation__getCreator = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocumentInformation__getCreator(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDDocumentInformation, + "org/apache/pdfbox/pdmodel/PDDocumentInformation"); + if (_c_PDDocumentInformation == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocumentInformation, &_m_PDDocumentInformation__getCreator, + "getCreator", "()Ljava/lang/String;"); + if (_m_PDDocumentInformation__getCreator == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_PDDocumentInformation__getCreator); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocumentInformation__setCreator = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocumentInformation__setCreator(jobject self_, jobject creator) { + load_env(); + load_class_global_ref(&_c_PDDocumentInformation, + "org/apache/pdfbox/pdmodel/PDDocumentInformation"); + if (_c_PDDocumentInformation == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocumentInformation, &_m_PDDocumentInformation__setCreator, + "setCreator", "(Ljava/lang/String;)V"); + if (_m_PDDocumentInformation__setCreator == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDDocumentInformation__setCreator, + creator); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDDocumentInformation__getProducer = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocumentInformation__getProducer(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDDocumentInformation, + "org/apache/pdfbox/pdmodel/PDDocumentInformation"); + if (_c_PDDocumentInformation == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocumentInformation, &_m_PDDocumentInformation__getProducer, + "getProducer", "()Ljava/lang/String;"); + if (_m_PDDocumentInformation__getProducer == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_PDDocumentInformation__getProducer); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocumentInformation__setProducer = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocumentInformation__setProducer(jobject self_, jobject producer) { + load_env(); + load_class_global_ref(&_c_PDDocumentInformation, + "org/apache/pdfbox/pdmodel/PDDocumentInformation"); + if (_c_PDDocumentInformation == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocumentInformation, &_m_PDDocumentInformation__setProducer, + "setProducer", "(Ljava/lang/String;)V"); + if (_m_PDDocumentInformation__setProducer == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, + _m_PDDocumentInformation__setProducer, producer); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDDocumentInformation__getCreationDate = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocumentInformation__getCreationDate(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDDocumentInformation, + "org/apache/pdfbox/pdmodel/PDDocumentInformation"); + if (_c_PDDocumentInformation == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocumentInformation, + &_m_PDDocumentInformation__getCreationDate, "getCreationDate", + "()Ljava/util/Calendar;"); + if (_m_PDDocumentInformation__getCreationDate == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_PDDocumentInformation__getCreationDate); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocumentInformation__setCreationDate = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocumentInformation__setCreationDate(jobject self_, jobject date) { + load_env(); + load_class_global_ref(&_c_PDDocumentInformation, + "org/apache/pdfbox/pdmodel/PDDocumentInformation"); + if (_c_PDDocumentInformation == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocumentInformation, + &_m_PDDocumentInformation__setCreationDate, "setCreationDate", + "(Ljava/util/Calendar;)V"); + if (_m_PDDocumentInformation__setCreationDate == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, + _m_PDDocumentInformation__setCreationDate, date); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDDocumentInformation__getModificationDate = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocumentInformation__getModificationDate(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDDocumentInformation, + "org/apache/pdfbox/pdmodel/PDDocumentInformation"); + if (_c_PDDocumentInformation == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocumentInformation, + &_m_PDDocumentInformation__getModificationDate, + "getModificationDate", "()Ljava/util/Calendar;"); + if (_m_PDDocumentInformation__getModificationDate == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_PDDocumentInformation__getModificationDate); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocumentInformation__setModificationDate = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocumentInformation__setModificationDate(jobject self_, + jobject date) { + load_env(); + load_class_global_ref(&_c_PDDocumentInformation, + "org/apache/pdfbox/pdmodel/PDDocumentInformation"); + if (_c_PDDocumentInformation == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocumentInformation, + &_m_PDDocumentInformation__setModificationDate, + "setModificationDate", "(Ljava/util/Calendar;)V"); + if (_m_PDDocumentInformation__setModificationDate == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod( + jniEnv, self_, _m_PDDocumentInformation__setModificationDate, date); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDDocumentInformation__getTrapped = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocumentInformation__getTrapped(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDDocumentInformation, + "org/apache/pdfbox/pdmodel/PDDocumentInformation"); + if (_c_PDDocumentInformation == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocumentInformation, &_m_PDDocumentInformation__getTrapped, + "getTrapped", "()Ljava/lang/String;"); + if (_m_PDDocumentInformation__getTrapped == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_PDDocumentInformation__getTrapped); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocumentInformation__getMetadataKeys = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocumentInformation__getMetadataKeys(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDDocumentInformation, + "org/apache/pdfbox/pdmodel/PDDocumentInformation"); + if (_c_PDDocumentInformation == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocumentInformation, + &_m_PDDocumentInformation__getMetadataKeys, "getMetadataKeys", + "()Ljava/util/Set;"); + if (_m_PDDocumentInformation__getMetadataKeys == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_PDDocumentInformation__getMetadataKeys); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocumentInformation__getCustomMetadataValue = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocumentInformation__getCustomMetadataValue(jobject self_, + jobject fieldName) { + load_env(); + load_class_global_ref(&_c_PDDocumentInformation, + "org/apache/pdfbox/pdmodel/PDDocumentInformation"); + if (_c_PDDocumentInformation == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocumentInformation, + &_m_PDDocumentInformation__getCustomMetadataValue, + "getCustomMetadataValue", + "(Ljava/lang/String;)Ljava/lang/String;"); + if (_m_PDDocumentInformation__getCustomMetadataValue == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_PDDocumentInformation__getCustomMetadataValue, + fieldName); + return to_global_ref_result(_result); +} + +jmethodID _m_PDDocumentInformation__setCustomMetadataValue = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocumentInformation__setCustomMetadataValue(jobject self_, + jobject fieldName, + jobject fieldValue) { + load_env(); + load_class_global_ref(&_c_PDDocumentInformation, + "org/apache/pdfbox/pdmodel/PDDocumentInformation"); + if (_c_PDDocumentInformation == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocumentInformation, + &_m_PDDocumentInformation__setCustomMetadataValue, + "setCustomMetadataValue", + "(Ljava/lang/String;Ljava/lang/String;)V"); + if (_m_PDDocumentInformation__setCustomMetadataValue == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, + _m_PDDocumentInformation__setCustomMetadataValue, + fieldName, fieldValue); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDDocumentInformation__setTrapped = NULL; +FFI_PLUGIN_EXPORT +JniResult PDDocumentInformation__setTrapped(jobject self_, jobject value) { + load_env(); + load_class_global_ref(&_c_PDDocumentInformation, + "org/apache/pdfbox/pdmodel/PDDocumentInformation"); + if (_c_PDDocumentInformation == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDDocumentInformation, &_m_PDDocumentInformation__setTrapped, + "setTrapped", "(Ljava/lang/String;)V"); + if (_m_PDDocumentInformation__setTrapped == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDDocumentInformation__setTrapped, + value); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +// org.apache.pdfbox.text.PDFTextStripper +jclass _c_PDFTextStripper = NULL; + +jmethodID _m_PDFTextStripper__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__new0() { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__new0, "", "()V"); + if (_m_PDFTextStripper__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject(jniEnv, _c_PDFTextStripper, + _m_PDFTextStripper__new0); + return to_global_ref_result(_result); +} + +jmethodID _m_PDFTextStripper__getText = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__getText(jobject self_, jobject doc) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__getText, "getText", + "(Lorg/apache/pdfbox/pdmodel/PDDocument;)Ljava/lang/String;"); + if (_m_PDFTextStripper__getText == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_PDFTextStripper__getText, doc); + return to_global_ref_result(_result); +} + +jmethodID _m_PDFTextStripper__writeText = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__writeText(jobject self_, + jobject doc, + jobject outputStream) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__writeText, "writeText", + "(Lorg/apache/pdfbox/pdmodel/PDDocument;Ljava/io/Writer;)V"); + if (_m_PDFTextStripper__writeText == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDFTextStripper__writeText, doc, + outputStream); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__processPages = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__processPages(jobject self_, jobject pages) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__processPages, + "processPages", "(Lorg/apache/pdfbox/pdmodel/PDPageTree;)V"); + if (_m_PDFTextStripper__processPages == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDFTextStripper__processPages, + pages); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__startDocument = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__startDocument(jobject self_, jobject document) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__startDocument, + "startDocument", "(Lorg/apache/pdfbox/pdmodel/PDDocument;)V"); + if (_m_PDFTextStripper__startDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDFTextStripper__startDocument, + document); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__endDocument = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__endDocument(jobject self_, jobject document) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__endDocument, + "endDocument", "(Lorg/apache/pdfbox/pdmodel/PDDocument;)V"); + if (_m_PDFTextStripper__endDocument == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDFTextStripper__endDocument, + document); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__processPage = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__processPage(jobject self_, jobject page) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__processPage, + "processPage", "(Lorg/apache/pdfbox/pdmodel/PDPage;)V"); + if (_m_PDFTextStripper__processPage == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDFTextStripper__processPage, + page); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__startArticle = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__startArticle(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__startArticle, + "startArticle", "()V"); + if (_m_PDFTextStripper__startArticle == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDFTextStripper__startArticle); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__startArticle1 = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__startArticle1(jobject self_, uint8_t isLTR) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__startArticle1, + "startArticle", "(Z)V"); + if (_m_PDFTextStripper__startArticle1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDFTextStripper__startArticle1, + isLTR); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__endArticle = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__endArticle(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__endArticle, "endArticle", + "()V"); + if (_m_PDFTextStripper__endArticle == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDFTextStripper__endArticle); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__startPage = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__startPage(jobject self_, jobject page) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__startPage, "startPage", + "(Lorg/apache/pdfbox/pdmodel/PDPage;)V"); + if (_m_PDFTextStripper__startPage == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDFTextStripper__startPage, page); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__endPage = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__endPage(jobject self_, jobject page) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__endPage, "endPage", + "(Lorg/apache/pdfbox/pdmodel/PDPage;)V"); + if (_m_PDFTextStripper__endPage == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDFTextStripper__endPage, page); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__writePage = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__writePage(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__writePage, "writePage", + "()V"); + if (_m_PDFTextStripper__writePage == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDFTextStripper__writePage); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__writeLineSeparator = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__writeLineSeparator(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__writeLineSeparator, + "writeLineSeparator", "()V"); + if (_m_PDFTextStripper__writeLineSeparator == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, + _m_PDFTextStripper__writeLineSeparator); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__writeWordSeparator = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__writeWordSeparator(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__writeWordSeparator, + "writeWordSeparator", "()V"); + if (_m_PDFTextStripper__writeWordSeparator == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, + _m_PDFTextStripper__writeWordSeparator); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__writeCharacters = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__writeCharacters(jobject self_, jobject text) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__writeCharacters, + "writeCharacters", "(Lorg/apache/pdfbox/text/TextPosition;)V"); + if (_m_PDFTextStripper__writeCharacters == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDFTextStripper__writeCharacters, + text); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__writeString = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__writeString(jobject self_, + jobject text, + jobject textPositions) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__writeString, + "writeString", "(Ljava/lang/String;Ljava/util/List;)V"); + if (_m_PDFTextStripper__writeString == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDFTextStripper__writeString, + text, textPositions); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__writeString1 = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__writeString1(jobject self_, jobject text) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__writeString1, + "writeString", "(Ljava/lang/String;)V"); + if (_m_PDFTextStripper__writeString1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDFTextStripper__writeString1, + text); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__processTextPosition = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__processTextPosition(jobject self_, jobject text) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__processTextPosition, + "processTextPosition", + "(Lorg/apache/pdfbox/text/TextPosition;)V"); + if (_m_PDFTextStripper__processTextPosition == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, + _m_PDFTextStripper__processTextPosition, text); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__getStartPage = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__getStartPage(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__getStartPage, + "getStartPage", "()I"); + if (_m_PDFTextStripper__getStartPage == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = + (*jniEnv)->CallIntMethod(jniEnv, self_, _m_PDFTextStripper__getStartPage); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__setStartPage = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__setStartPage(jobject self_, int32_t startPageValue) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__setStartPage, + "setStartPage", "(I)V"); + if (_m_PDFTextStripper__setStartPage == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDFTextStripper__setStartPage, + startPageValue); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__getEndPage = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__getEndPage(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__getEndPage, "getEndPage", + "()I"); + if (_m_PDFTextStripper__getEndPage == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = + (*jniEnv)->CallIntMethod(jniEnv, self_, _m_PDFTextStripper__getEndPage); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__setEndPage = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__setEndPage(jobject self_, int32_t endPageValue) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__setEndPage, "setEndPage", + "(I)V"); + if (_m_PDFTextStripper__setEndPage == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDFTextStripper__setEndPage, + endPageValue); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__setLineSeparator = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__setLineSeparator(jobject self_, jobject separator) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__setLineSeparator, + "setLineSeparator", "(Ljava/lang/String;)V"); + if (_m_PDFTextStripper__setLineSeparator == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDFTextStripper__setLineSeparator, + separator); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__getLineSeparator = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__getLineSeparator(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__getLineSeparator, + "getLineSeparator", "()Ljava/lang/String;"); + if (_m_PDFTextStripper__getLineSeparator == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_PDFTextStripper__getLineSeparator); + return to_global_ref_result(_result); +} + +jmethodID _m_PDFTextStripper__getWordSeparator = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__getWordSeparator(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__getWordSeparator, + "getWordSeparator", "()Ljava/lang/String;"); + if (_m_PDFTextStripper__getWordSeparator == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_PDFTextStripper__getWordSeparator); + return to_global_ref_result(_result); +} + +jmethodID _m_PDFTextStripper__setWordSeparator = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__setWordSeparator(jobject self_, jobject separator) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__setWordSeparator, + "setWordSeparator", "(Ljava/lang/String;)V"); + if (_m_PDFTextStripper__setWordSeparator == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDFTextStripper__setWordSeparator, + separator); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__getSuppressDuplicateOverlappingText = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__getSuppressDuplicateOverlappingText(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, + &_m_PDFTextStripper__getSuppressDuplicateOverlappingText, + "getSuppressDuplicateOverlappingText", "()Z"); + if (_m_PDFTextStripper__getSuppressDuplicateOverlappingText == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod( + jniEnv, self_, _m_PDFTextStripper__getSuppressDuplicateOverlappingText); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__getCurrentPageNo = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__getCurrentPageNo(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__getCurrentPageNo, + "getCurrentPageNo", "()I"); + if (_m_PDFTextStripper__getCurrentPageNo == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = (*jniEnv)->CallIntMethod( + jniEnv, self_, _m_PDFTextStripper__getCurrentPageNo); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__getOutput = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__getOutput(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__getOutput, "getOutput", + "()Ljava/io/Writer;"); + if (_m_PDFTextStripper__getOutput == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_PDFTextStripper__getOutput); + return to_global_ref_result(_result); +} + +jmethodID _m_PDFTextStripper__getCharactersByArticle = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__getCharactersByArticle(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__getCharactersByArticle, + "getCharactersByArticle", "()Ljava/util/List;"); + if (_m_PDFTextStripper__getCharactersByArticle == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_PDFTextStripper__getCharactersByArticle); + return to_global_ref_result(_result); +} + +jmethodID _m_PDFTextStripper__setSuppressDuplicateOverlappingText = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__setSuppressDuplicateOverlappingText( + jobject self_, + uint8_t suppressDuplicateOverlappingTextValue) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, + &_m_PDFTextStripper__setSuppressDuplicateOverlappingText, + "setSuppressDuplicateOverlappingText", "(Z)V"); + if (_m_PDFTextStripper__setSuppressDuplicateOverlappingText == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod( + jniEnv, self_, _m_PDFTextStripper__setSuppressDuplicateOverlappingText, + suppressDuplicateOverlappingTextValue); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__getSeparateByBeads = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__getSeparateByBeads(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__getSeparateByBeads, + "getSeparateByBeads", "()Z"); + if (_m_PDFTextStripper__getSeparateByBeads == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod( + jniEnv, self_, _m_PDFTextStripper__getSeparateByBeads); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__setShouldSeparateByBeads = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__setShouldSeparateByBeads( + jobject self_, + uint8_t aShouldSeparateByBeads) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__setShouldSeparateByBeads, + "setShouldSeparateByBeads", "(Z)V"); + if (_m_PDFTextStripper__setShouldSeparateByBeads == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, + _m_PDFTextStripper__setShouldSeparateByBeads, + aShouldSeparateByBeads); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__getEndBookmark = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__getEndBookmark(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__getEndBookmark, + "getEndBookmark", + "()Lorg/apache/pdfbox/pdmodel/interactive/documentnavigation/" + "outline/PDOutlineItem;"); + if (_m_PDFTextStripper__getEndBookmark == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_PDFTextStripper__getEndBookmark); + return to_global_ref_result(_result); +} + +jmethodID _m_PDFTextStripper__setEndBookmark = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__setEndBookmark(jobject self_, jobject aEndBookmark) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__setEndBookmark, + "setEndBookmark", + "(Lorg/apache/pdfbox/pdmodel/interactive/documentnavigation/" + "outline/PDOutlineItem;)V"); + if (_m_PDFTextStripper__setEndBookmark == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDFTextStripper__setEndBookmark, + aEndBookmark); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__getStartBookmark = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__getStartBookmark(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__getStartBookmark, + "getStartBookmark", + "()Lorg/apache/pdfbox/pdmodel/interactive/documentnavigation/" + "outline/PDOutlineItem;"); + if (_m_PDFTextStripper__getStartBookmark == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_PDFTextStripper__getStartBookmark); + return to_global_ref_result(_result); +} + +jmethodID _m_PDFTextStripper__setStartBookmark = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__setStartBookmark(jobject self_, + jobject aStartBookmark) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__setStartBookmark, + "setStartBookmark", + "(Lorg/apache/pdfbox/pdmodel/interactive/documentnavigation/" + "outline/PDOutlineItem;)V"); + if (_m_PDFTextStripper__setStartBookmark == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDFTextStripper__setStartBookmark, + aStartBookmark); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__getAddMoreFormatting = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__getAddMoreFormatting(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__getAddMoreFormatting, + "getAddMoreFormatting", "()Z"); + if (_m_PDFTextStripper__getAddMoreFormatting == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod( + jniEnv, self_, _m_PDFTextStripper__getAddMoreFormatting); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__setAddMoreFormatting = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__setAddMoreFormatting(jobject self_, + uint8_t newAddMoreFormatting) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__setAddMoreFormatting, + "setAddMoreFormatting", "(Z)V"); + if (_m_PDFTextStripper__setAddMoreFormatting == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, + _m_PDFTextStripper__setAddMoreFormatting, + newAddMoreFormatting); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__getSortByPosition = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__getSortByPosition(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__getSortByPosition, + "getSortByPosition", "()Z"); + if (_m_PDFTextStripper__getSortByPosition == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod( + jniEnv, self_, _m_PDFTextStripper__getSortByPosition); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__setSortByPosition = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__setSortByPosition(jobject self_, + uint8_t newSortByPosition) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__setSortByPosition, + "setSortByPosition", "(Z)V"); + if (_m_PDFTextStripper__setSortByPosition == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod( + jniEnv, self_, _m_PDFTextStripper__setSortByPosition, newSortByPosition); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__getSpacingTolerance = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__getSpacingTolerance(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__getSpacingTolerance, + "getSpacingTolerance", "()F"); + if (_m_PDFTextStripper__getSpacingTolerance == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + float _result = (*jniEnv)->CallFloatMethod( + jniEnv, self_, _m_PDFTextStripper__getSpacingTolerance); + return (JniResult){.value = {.f = _result}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__setSpacingTolerance = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__setSpacingTolerance(jobject self_, + float spacingToleranceValue) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__setSpacingTolerance, + "setSpacingTolerance", "(F)V"); + if (_m_PDFTextStripper__setSpacingTolerance == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, + _m_PDFTextStripper__setSpacingTolerance, + spacingToleranceValue); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__getAverageCharTolerance = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__getAverageCharTolerance(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__getAverageCharTolerance, + "getAverageCharTolerance", "()F"); + if (_m_PDFTextStripper__getAverageCharTolerance == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + float _result = (*jniEnv)->CallFloatMethod( + jniEnv, self_, _m_PDFTextStripper__getAverageCharTolerance); + return (JniResult){.value = {.f = _result}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__setAverageCharTolerance = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__setAverageCharTolerance( + jobject self_, + float averageCharToleranceValue) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__setAverageCharTolerance, + "setAverageCharTolerance", "(F)V"); + if (_m_PDFTextStripper__setAverageCharTolerance == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, + _m_PDFTextStripper__setAverageCharTolerance, + averageCharToleranceValue); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__getIndentThreshold = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__getIndentThreshold(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__getIndentThreshold, + "getIndentThreshold", "()F"); + if (_m_PDFTextStripper__getIndentThreshold == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + float _result = (*jniEnv)->CallFloatMethod( + jniEnv, self_, _m_PDFTextStripper__getIndentThreshold); + return (JniResult){.value = {.f = _result}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__setIndentThreshold = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__setIndentThreshold(jobject self_, + float indentThresholdValue) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__setIndentThreshold, + "setIndentThreshold", "(F)V"); + if (_m_PDFTextStripper__setIndentThreshold == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, + _m_PDFTextStripper__setIndentThreshold, + indentThresholdValue); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__getDropThreshold = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__getDropThreshold(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__getDropThreshold, + "getDropThreshold", "()F"); + if (_m_PDFTextStripper__getDropThreshold == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + float _result = (*jniEnv)->CallFloatMethod( + jniEnv, self_, _m_PDFTextStripper__getDropThreshold); + return (JniResult){.value = {.f = _result}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__setDropThreshold = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__setDropThreshold(jobject self_, + float dropThresholdValue) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__setDropThreshold, + "setDropThreshold", "(F)V"); + if (_m_PDFTextStripper__setDropThreshold == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDFTextStripper__setDropThreshold, + dropThresholdValue); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__getParagraphStart = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__getParagraphStart(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__getParagraphStart, + "getParagraphStart", "()Ljava/lang/String;"); + if (_m_PDFTextStripper__getParagraphStart == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_PDFTextStripper__getParagraphStart); + return to_global_ref_result(_result); +} + +jmethodID _m_PDFTextStripper__setParagraphStart = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__setParagraphStart(jobject self_, jobject s) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__setParagraphStart, + "setParagraphStart", "(Ljava/lang/String;)V"); + if (_m_PDFTextStripper__setParagraphStart == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, + _m_PDFTextStripper__setParagraphStart, s); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__getParagraphEnd = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__getParagraphEnd(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__getParagraphEnd, + "getParagraphEnd", "()Ljava/lang/String;"); + if (_m_PDFTextStripper__getParagraphEnd == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_PDFTextStripper__getParagraphEnd); + return to_global_ref_result(_result); +} + +jmethodID _m_PDFTextStripper__setParagraphEnd = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__setParagraphEnd(jobject self_, jobject s) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__setParagraphEnd, + "setParagraphEnd", "(Ljava/lang/String;)V"); + if (_m_PDFTextStripper__setParagraphEnd == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDFTextStripper__setParagraphEnd, + s); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__getPageStart = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__getPageStart(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__getPageStart, + "getPageStart", "()Ljava/lang/String;"); + if (_m_PDFTextStripper__getPageStart == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_PDFTextStripper__getPageStart); + return to_global_ref_result(_result); +} + +jmethodID _m_PDFTextStripper__setPageStart = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__setPageStart(jobject self_, jobject pageStartValue) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__setPageStart, + "setPageStart", "(Ljava/lang/String;)V"); + if (_m_PDFTextStripper__setPageStart == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDFTextStripper__setPageStart, + pageStartValue); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__getPageEnd = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__getPageEnd(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__getPageEnd, "getPageEnd", + "()Ljava/lang/String;"); + if (_m_PDFTextStripper__getPageEnd == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod(jniEnv, self_, + _m_PDFTextStripper__getPageEnd); + return to_global_ref_result(_result); +} + +jmethodID _m_PDFTextStripper__setPageEnd = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__setPageEnd(jobject self_, jobject pageEndValue) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__setPageEnd, "setPageEnd", + "(Ljava/lang/String;)V"); + if (_m_PDFTextStripper__setPageEnd == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDFTextStripper__setPageEnd, + pageEndValue); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__getArticleStart = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__getArticleStart(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__getArticleStart, + "getArticleStart", "()Ljava/lang/String;"); + if (_m_PDFTextStripper__getArticleStart == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_PDFTextStripper__getArticleStart); + return to_global_ref_result(_result); +} + +jmethodID _m_PDFTextStripper__setArticleStart = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__setArticleStart(jobject self_, + jobject articleStartValue) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__setArticleStart, + "setArticleStart", "(Ljava/lang/String;)V"); + if (_m_PDFTextStripper__setArticleStart == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDFTextStripper__setArticleStart, + articleStartValue); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__getArticleEnd = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__getArticleEnd(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__getArticleEnd, + "getArticleEnd", "()Ljava/lang/String;"); + if (_m_PDFTextStripper__getArticleEnd == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_PDFTextStripper__getArticleEnd); + return to_global_ref_result(_result); +} + +jmethodID _m_PDFTextStripper__setArticleEnd = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__setArticleEnd(jobject self_, + jobject articleEndValue) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__setArticleEnd, + "setArticleEnd", "(Ljava/lang/String;)V"); + if (_m_PDFTextStripper__setArticleEnd == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDFTextStripper__setArticleEnd, + articleEndValue); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__writeParagraphSeparator = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__writeParagraphSeparator(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__writeParagraphSeparator, + "writeParagraphSeparator", "()V"); + if (_m_PDFTextStripper__writeParagraphSeparator == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, + _m_PDFTextStripper__writeParagraphSeparator); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__writeParagraphStart = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__writeParagraphStart(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__writeParagraphStart, + "writeParagraphStart", "()V"); + if (_m_PDFTextStripper__writeParagraphStart == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, + _m_PDFTextStripper__writeParagraphStart); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__writeParagraphEnd = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__writeParagraphEnd(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__writeParagraphEnd, + "writeParagraphEnd", "()V"); + if (_m_PDFTextStripper__writeParagraphEnd == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, + _m_PDFTextStripper__writeParagraphEnd); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__writePageStart = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__writePageStart(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__writePageStart, + "writePageStart", "()V"); + if (_m_PDFTextStripper__writePageStart == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDFTextStripper__writePageStart); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__writePageEnd = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__writePageEnd(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__writePageEnd, + "writePageEnd", "()V"); + if (_m_PDFTextStripper__writePageEnd == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_PDFTextStripper__writePageEnd); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__setListItemPatterns = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__setListItemPatterns(jobject self_, + jobject patterns) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__setListItemPatterns, + "setListItemPatterns", "(Ljava/util/List;)V"); + if (_m_PDFTextStripper__setListItemPatterns == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, + _m_PDFTextStripper__setListItemPatterns, patterns); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_PDFTextStripper__getListItemPatterns = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__getListItemPatterns(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_PDFTextStripper, &_m_PDFTextStripper__getListItemPatterns, + "getListItemPatterns", "()Ljava/util/List;"); + if (_m_PDFTextStripper__getListItemPatterns == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_PDFTextStripper__getListItemPatterns); + return to_global_ref_result(_result); +} + +jmethodID _m_PDFTextStripper__matchPattern = NULL; +FFI_PLUGIN_EXPORT +JniResult PDFTextStripper__matchPattern(jobject string, jobject patterns) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method( + _c_PDFTextStripper, &_m_PDFTextStripper__matchPattern, "matchPattern", + "(Ljava/lang/String;Ljava/util/List;)Ljava/util/regex/Pattern;"); + if (_m_PDFTextStripper__matchPattern == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_PDFTextStripper, _m_PDFTextStripper__matchPattern, string, + patterns); + return to_global_ref_result(_result); +} + +jfieldID _f_PDFTextStripper__LINE_SEPARATOR = NULL; +FFI_PLUGIN_EXPORT +JniResult get_PDFTextStripper__LINE_SEPARATOR(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_PDFTextStripper, &_f_PDFTextStripper__LINE_SEPARATOR, + "LINE_SEPARATOR", "Ljava/lang/String;"); + jobject _result = (*jniEnv)->GetObjectField( + jniEnv, self_, _f_PDFTextStripper__LINE_SEPARATOR); + return to_global_ref_result(_result); +} + +jfieldID _f_PDFTextStripper__charactersByArticle = NULL; +FFI_PLUGIN_EXPORT +JniResult get_PDFTextStripper__charactersByArticle(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_PDFTextStripper, &_f_PDFTextStripper__charactersByArticle, + "charactersByArticle", "Ljava/util/ArrayList;"); + jobject _result = (*jniEnv)->GetObjectField( + jniEnv, self_, _f_PDFTextStripper__charactersByArticle); + return to_global_ref_result(_result); +} + +FFI_PLUGIN_EXPORT +JniResult set_PDFTextStripper__charactersByArticle(jobject self_, + jobject value) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_PDFTextStripper, &_f_PDFTextStripper__charactersByArticle, + "charactersByArticle", "Ljava/util/ArrayList;"); + (*jniEnv)->SetObjectField(jniEnv, self_, + _f_PDFTextStripper__charactersByArticle, value); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jfieldID _f_PDFTextStripper__document = NULL; +FFI_PLUGIN_EXPORT +JniResult get_PDFTextStripper__document(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_PDFTextStripper, &_f_PDFTextStripper__document, "document", + "Lorg/apache/pdfbox/pdmodel/PDDocument;"); + jobject _result = + (*jniEnv)->GetObjectField(jniEnv, self_, _f_PDFTextStripper__document); + return to_global_ref_result(_result); +} + +FFI_PLUGIN_EXPORT +JniResult set_PDFTextStripper__document(jobject self_, jobject value) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_PDFTextStripper, &_f_PDFTextStripper__document, "document", + "Lorg/apache/pdfbox/pdmodel/PDDocument;"); + (*jniEnv)->SetObjectField(jniEnv, self_, _f_PDFTextStripper__document, value); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jfieldID _f_PDFTextStripper__output = NULL; +FFI_PLUGIN_EXPORT +JniResult get_PDFTextStripper__output(jobject self_) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_PDFTextStripper, &_f_PDFTextStripper__output, "output", + "Ljava/io/Writer;"); + jobject _result = + (*jniEnv)->GetObjectField(jniEnv, self_, _f_PDFTextStripper__output); + return to_global_ref_result(_result); +} + +FFI_PLUGIN_EXPORT +JniResult set_PDFTextStripper__output(jobject self_, jobject value) { + load_env(); + load_class_global_ref(&_c_PDFTextStripper, + "org/apache/pdfbox/text/PDFTextStripper"); + if (_c_PDFTextStripper == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_PDFTextStripper, &_f_PDFTextStripper__output, "output", + "Ljava/io/Writer;"); + (*jniEnv)->SetObjectField(jniEnv, self_, _f_PDFTextStripper__output, value); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} diff --git a/pkgs/jnigen/example/pdfbox_plugin/windows/.gitignore b/pkgs/jnigen/example/pdfbox_plugin/windows/.gitignore new file mode 100644 index 000000000..b3eb2be16 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/windows/.gitignore @@ -0,0 +1,17 @@ +flutter/ + +# Visual Studio user-specific files. +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual Studio build-related files. +x64/ +x86/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ diff --git a/pkgs/jnigen/example/pdfbox_plugin/windows/CMakeLists.txt b/pkgs/jnigen/example/pdfbox_plugin/windows/CMakeLists.txt new file mode 100644 index 000000000..3d9bd5c70 --- /dev/null +++ b/pkgs/jnigen/example/pdfbox_plugin/windows/CMakeLists.txt @@ -0,0 +1,23 @@ +# The Flutter tooling requires that developers have a version of Visual Studio +# installed that includes CMake 3.14 or later. You should not increase this +# version, as doing so will cause the plugin to fail to compile for some +# customers of the plugin. +cmake_minimum_required(VERSION 3.14) + +# Project-level configuration. +set(PROJECT_NAME "pdfbox_plugin") +project(${PROJECT_NAME} LANGUAGES CXX) + +# Invoke the build for native code shared with the other target platforms. +# This can be changed to accomodate different builds. +add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../src" "${CMAKE_CURRENT_BINARY_DIR}/shared") + +# List of absolute paths to libraries that should be bundled with the plugin. +# This list could contain prebuilt libraries, or libraries created by an +# external build triggered from this build file. +set(pdfbox_plugin_bundled_libraries + # Defined in ../src/CMakeLists.txt. + # This can be changed to accomodate different builds. + $ + PARENT_SCOPE +) diff --git a/pkgs/jnigen/java/.gitignore b/pkgs/jnigen/java/.gitignore new file mode 100644 index 000000000..5ccba1795 --- /dev/null +++ b/pkgs/jnigen/java/.gitignore @@ -0,0 +1,12 @@ +target/* +*.class +*.jar + +.idea/compiler.xml +.idea/dictionaries +.idea/inspectionProfiles/ +.idea/jarRepositories.xml +.idea/misc.xml +.idea/runConfigurations.xml + +.classpath ## Used for experimenting with JShell REPL diff --git a/pkgs/jnigen/java/README.md b/pkgs/jnigen/java/README.md new file mode 100644 index 000000000..8b15049a8 --- /dev/null +++ b/pkgs/jnigen/java/README.md @@ -0,0 +1,51 @@ +## ApiSummarizer + +An early version of ApiSummarizer. + +It analyzes java source code / jars and outputs a JSON representation of the public API. + +It's currently used in `jnigen` to get the information of the Java API. + +## Build + +When using it via `jnigen`, the `jnigen:setup` script will take care of building the jar in appropriate location. + +To build the jar manually, run `mvn compile` in project root. To build the jar and run the tests as well, run `mvn test`. The jar will be created in `target/` directory. + +## Command line + +``` +usage: java -jar [-s ] [-c ] + +Class or package names should be fully qualified. + +-b,--backend backend to use for summary generation ('doclet' +or 'asm'). +-c,--classes paths to search for compiled classes +-D,--doctool-args Arguments to pass to the documentation tool +-M,--use-modules use Java modules +-m,--module-names comma separated list of module names +-r,--recursive Include dependencies of classes +-s,--sources paths to search for source files +-v,--verbose Enable verbose output +``` + +Here class or package names are specified as fully qualified names, for example `org.apache.pdfbox.pdmodel.PDDocument` will load `org/apache/pdfbox/pdmodel/PDDocument.java`. It assumes the package naming reflects directory structure. If such mapping results in a directory, for example `android.os` is given and a directory `android/os` is found under the source path, it is considered as a package and all Java source files under that directory are loaded recursively. + +Note that some options are directly forwarded to the underlying tool. + +ApiSummarizer's current use is in `jnigen` for obtaining public API of java packages. Only the features strictly required for that purpose are focused upon. + +## Running tests + +Run `mvn surefire:test` + +There are not many tests at the moment. We plan to add some later. + +## ASM backend + +The main backend is based on javadoc API and generates summary based on java sources. A more experimental ASM backend also exists, and works somewhat okay-ish. It can summarize the compiled JARs. However, compiled jars without debug information do not include method parameter names. Some basic renaming is applied, i.e If type is `Object`, the parameter name will be output as `object` if an actual name is absent. + +## TODO + +See issue #23. diff --git a/pkgs/jnigen/java/pom.xml b/pkgs/jnigen/java/pom.xml new file mode 100644 index 000000000..226bb03fc --- /dev/null +++ b/pkgs/jnigen/java/pom.xml @@ -0,0 +1,110 @@ + + + 4.0.0 + + com.github.dart_lang.jnigen + ApiSummarizer + Summarize public APIs of java packages in JSON or protobuf. + 0.0.1-SNAPSHOT + + + 11 + 11 + 2.14.0-rc2 + UTF-8 + ${user.dir} + + + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + commons-cli + commons-cli + 1.5.0 + + + org.ow2.asm + asm-tree + 9.3 + + + org.jetbrains.kotlinx + kotlinx-metadata-jvm + 0.6.2 + + + junit + junit + 4.13.2 + test + + + + + ${buildDir}/target + ApiSummarizer + + + + maven-clean-plugin + 3.2.0 + + + maven-resources-plugin + 3.3.1 + + + maven-jar-plugin + 3.3.0 + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0-M7 + + + org.apache.maven.plugins + maven-assembly-plugin + 3.5.0 + + + jar-with-dependencies + + false + + + com.github.dart_lang.jnigen.apisummarizer.Main + + + + + + make-assembly + compile + + single + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.10.1 + + 11 + 11 + + + + + 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 new file mode 100644 index 000000000..0077fd71e --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/Main.java @@ -0,0 +1,151 @@ +// 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.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.ClassFinder; +import com.github.dart_lang.jnigen.apisummarizer.util.InputStreamProvider; +import com.github.dart_lang.jnigen.apisummarizer.util.JsonWriter; +import com.github.dart_lang.jnigen.apisummarizer.util.StreamUtil; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import javax.tools.DocumentationTool; +import javax.tools.JavaFileObject; +import javax.tools.ToolProvider; +import jdk.javadoc.doclet.Doclet; + +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, + } + + static SummarizerOptions options; + + public static List runDocletWithClass( + DocumentationTool javaDoc, + Class docletClass, + List fileObjects, + SummarizerOptions options) { + var fileManager = javaDoc.getStandardFileManager(null, null, null); + var cli = new ArrayList(); + cli.add((options.useModules ? "--module-" : "--") + "source-path=" + options.sourcePath); + if (options.classPath != null) { + cli.add("--class-path=" + options.classPath); + } + 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 runDoclet( + DocumentationTool javaDoc, List javaFileObjects, SummarizerOptions options) { + return runDocletWithClass(javaDoc, SummarizerDoclet.class, javaFileObjects, options); + } + + public static void main(String[] args) throws FileNotFoundException { + options = SummarizerOptions.parseArgs(args); + OutputStream output; + + if (options.outputFile == null || options.outputFile.equals("-")) { + output = System.out; + } else { + output = new FileOutputStream(options.outputFile); + } + List sourcePaths = + options.sourcePath != null + ? Arrays.asList(options.sourcePath.split(File.pathSeparator)) + : List.of(); + List classPaths = + options.classPath != null + ? Arrays.asList(options.classPath.split(File.pathSeparator)) + : List.of(); + + var javaDoc = ToolProvider.getSystemDocumentationTool(); + + var sourceClasses = new LinkedHashMap>(); + var binaryClasses = new LinkedHashMap>(); + + for (var qualifiedName : options.args) { + sourceClasses.put(qualifiedName, null); + binaryClasses.put(qualifiedName, null); + } + + if (options.backend != Backend.ASM) { + ClassFinder.findJavaSources( + sourceClasses, sourcePaths, javaDoc.getStandardFileManager(null, null, null)); + } + + // remove found classes from binaryClasses, so that they don't need to be searched again. + // TODO: Tidy up this logic, move to ClassFinder class + for (var qualifiedName : options.args) { + if (sourceClasses.get(qualifiedName) != null) { + binaryClasses.remove(qualifiedName); + } + } + + if (options.backend != Backend.DOCLET) { + ClassFinder.findJavaClasses(binaryClasses, classPaths); + } + + // remove duplicates (found as both source & binary), and determine if any class is not found. + var notFound = new ArrayList(); + for (var qualifiedName : options.args) { + var foundSource = sourceClasses.get(qualifiedName) != null; + var foundBinary = binaryClasses.get(qualifiedName) != null; + if (foundSource) { + binaryClasses.remove(qualifiedName); + } + if (!foundBinary && !foundSource) { + notFound.add(qualifiedName); + } + } + + if (!notFound.isEmpty()) { + System.err.println("Not found: " + notFound); + System.exit(1); + } + + var classStreamProviders = StreamUtil.flattenListValues(binaryClasses); + var sourceFiles = StreamUtil.flattenListValues(sourceClasses); + + switch (options.backend) { + case DOCLET: + JsonWriter.writeJSON(runDoclet(javaDoc, sourceFiles, options), output); + break; + case ASM: + JsonWriter.writeJSON(AsmSummarizer.run(classStreamProviders), output); + break; + case AUTO: + List decls = new ArrayList<>(); + if (!sourceFiles.isEmpty()) { + decls.addAll(runDoclet(javaDoc, sourceFiles, options)); + } + if (!classStreamProviders.isEmpty()) { + decls.addAll(AsmSummarizer.run(classStreamProviders)); + } + JsonWriter.writeJSON(decls, output); + break; + } + } +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/SummarizerOptions.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/SummarizerOptions.java new file mode 100644 index 000000000..8a3e5450c --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/SummarizerOptions.java @@ -0,0 +1,80 @@ +package com.github.dart_lang.jnigen.apisummarizer; + +import java.util.Arrays; +import org.apache.commons.cli.*; + +public class SummarizerOptions { + private static final CommandLineParser parser = new DefaultParser(); + String sourcePath; + String classPath; + boolean useModules; + Main.Backend backend; + String modulesList; + String toolArgs; + boolean verbose; + String outputFile; + String[] args; + + SummarizerOptions() {} + + public static SummarizerOptions fromCommandLine(CommandLine cmd) { + var opts = new SummarizerOptions(); + opts.sourcePath = cmd.getOptionValue("sources", null); + var backendString = cmd.getOptionValue("backend", "auto"); + opts.backend = Main.Backend.valueOf(backendString.toUpperCase()); + opts.classPath = cmd.getOptionValue("classes", null); + opts.useModules = cmd.hasOption("use-modules"); + opts.modulesList = cmd.getOptionValue("module-names", null); + opts.toolArgs = cmd.getOptionValue("doctool-args", null); + opts.outputFile = cmd.getOptionValue("output-file", null); + opts.args = cmd.getArgs(); + if (opts.args.length == 0) { + throw new IllegalArgumentException("Need one or more class or package names as arguments"); + } + return opts; + } + + 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', 'asm' or 'auto' (default))."); + Option useModules = new Option("M", "use-modules", false, "use Java modules"); + Option moduleNames = + new Option("m", "module-names", true, "comma separated list of module names"); + Option doctoolArgs = + new Option("D", "doctool-args", true, "arguments to pass to the documentation tool"); + Option outputFile = + new Option("o", "output-file", true, "write JSON to file instead of stdout"); + Option[] allOptions = { + sources, classes, backend, useModules, moduleNames, doctoolArgs, outputFile + }; + Arrays.stream(allOptions).forEach(options::addOption); + + HelpFormatter help = new HelpFormatter(); + + CommandLine cmd; + + try { + cmd = parser.parse(options, args); + if (cmd.getArgs().length < 1) { + throw new ParseException("Need to specify paths to source files"); + } + } catch (ParseException e) { + System.out.println(e.getMessage()); + help.printHelp( + "java -jar [-s ] " + + "[-c ] \n" + + "Class or package names should be fully qualified.\n\n", + options); + System.exit(1); + throw new RuntimeException("Unreachable code"); + } + return fromCommandLine(cmd); + } +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/AsmAnnotatedElementVisitor.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/AsmAnnotatedElementVisitor.java new file mode 100644 index 000000000..0a723b310 --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/AsmAnnotatedElementVisitor.java @@ -0,0 +1,23 @@ +// 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.disasm; + +import com.github.dart_lang.jnigen.apisummarizer.elements.JavaAnnotation; +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.Type; + +// This interface removes some repetitive code using default methods + +public interface AsmAnnotatedElementVisitor { + void addAnnotation(JavaAnnotation annotation); + + default AnnotationVisitor visitAnnotationDefault(String descriptor, boolean visible) { + var annotation = new JavaAnnotation(); + var aType = Type.getType(descriptor); + annotation.binaryName = aType.getClassName(); + addAnnotation(annotation); + return new AsmAnnotationVisitor(annotation); + } +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/AsmAnnotationVisitor.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/AsmAnnotationVisitor.java new file mode 100644 index 000000000..1323a45b7 --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/AsmAnnotationVisitor.java @@ -0,0 +1,84 @@ +// 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.disasm; + +import com.github.dart_lang.jnigen.apisummarizer.elements.JavaAnnotation; +import java.util.ArrayList; +import java.util.List; +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.Type; + +public class AsmAnnotationVisitor extends AnnotationVisitor { + + JavaAnnotation annotation; + + protected AsmAnnotationVisitor(JavaAnnotation annotation) { + super(AsmConstants.API); + this.annotation = annotation; + } + + @Override + public void visit(String name, Object value) { + annotation.properties.put(name, value); + } + + @Override + public void visitEnum(String name, String descriptor, String value) { + annotation.properties.put( + name, new JavaAnnotation.EnumVal(Type.getType(descriptor).getClassName(), value)); + } + + @Override + public AnnotationVisitor visitAnnotation(String name, String descriptor) { + var type = Type.getType(descriptor); + var nested = new JavaAnnotation(); + nested.binaryName = type.getClassName(); + annotation.properties.put(name, nested); + return new AsmAnnotationVisitor(nested); + } + + @Override + public AnnotationVisitor visitArray(String name) { + List list = new ArrayList<>(); + annotation.properties.put(name, list); + return new AnnotationArrayVisitor(list); + } + + public static class AnnotationArrayVisitor extends AnnotationVisitor { + List list; + + protected AnnotationArrayVisitor(List list) { + super(AsmConstants.API); + this.list = list; + } + + @Override + public void visit(String unused, Object value) { + list.add(value); + } + + @Override + public void visitEnum(String unused, String descriptor, String value) { + var type = Type.getType(descriptor); + list.add(new JavaAnnotation.EnumVal(type.getClassName(), value)); + } + + @Override + public AnnotationVisitor visitAnnotation(String unused, String descriptor) { + var type = Type.getType(descriptor); + var nested = new JavaAnnotation(); + nested.binaryName = type.getClassName(); + list.add(nested); + return new AsmAnnotationVisitor(nested); + } + + @Override + public AnnotationVisitor visitArray(String unused) { + List nested = new ArrayList<>(); + list.add(nested); + return new AnnotationArrayVisitor(nested); + } + } +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/AsmClassSignatureVisitor.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/AsmClassSignatureVisitor.java new file mode 100644 index 000000000..8805c7f14 --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/AsmClassSignatureVisitor.java @@ -0,0 +1,54 @@ +// 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.disasm; + +import com.github.dart_lang.jnigen.apisummarizer.elements.ClassDecl; +import com.github.dart_lang.jnigen.apisummarizer.elements.TypeParam; +import com.github.dart_lang.jnigen.apisummarizer.elements.TypeUsage; +import org.objectweb.asm.signature.SignatureVisitor; + +public class AsmClassSignatureVisitor extends SignatureVisitor { + private final ClassDecl decl; + private int interfaceIndex = -1; + + public AsmClassSignatureVisitor(ClassDecl decl) { + super(AsmConstants.API); + this.decl = decl; + } + + @Override + public void visitFormalTypeParameter(String name) { + var typeParam = new TypeParam(); + typeParam.name = name; + decl.typeParams.add(typeParam); + } + + @Override + public SignatureVisitor visitClassBound() { + var typeUsage = new TypeUsage(); + // ClassDecl initially has no type parameters. In visitFormalTypeParameter we add them + // and sequentially visitClassBound and visitInterfaceBound. + decl.typeParams.get(decl.typeParams.size() - 1).bounds.add(typeUsage); + return new AsmTypeUsageSignatureVisitor(typeUsage); + } + + @Override + public SignatureVisitor visitInterfaceBound() { + var typeUsage = new TypeUsage(); + decl.typeParams.get(decl.typeParams.size() - 1).bounds.add(typeUsage); + return new AsmTypeUsageSignatureVisitor(typeUsage); + } + + @Override + public SignatureVisitor visitSuperclass() { + return new AsmTypeUsageSignatureVisitor(decl.superclass); + } + + @Override + public SignatureVisitor visitInterface() { + interfaceIndex++; + return new AsmTypeUsageSignatureVisitor(decl.interfaces.get(interfaceIndex)); + } +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/AsmClassVisitor.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/AsmClassVisitor.java new file mode 100644 index 000000000..d5a730b47 --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/AsmClassVisitor.java @@ -0,0 +1,180 @@ +// 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.disasm; + +import static org.objectweb.asm.Opcodes.ACC_ENUM; + +import com.github.dart_lang.jnigen.apisummarizer.elements.*; +import com.github.dart_lang.jnigen.apisummarizer.util.SkipException; +import com.github.dart_lang.jnigen.apisummarizer.util.StreamUtil; +import java.util.*; +import java.util.stream.Collectors; +import org.objectweb.asm.*; +import org.objectweb.asm.signature.SignatureReader; + +public class AsmClassVisitor extends ClassVisitor implements AsmAnnotatedElementVisitor { + private static Param param( + Type type, String name, @SuppressWarnings("SameParameterValue") String signature) { + var param = new Param(); + param.name = name; + param.type = TypeUtils.typeUsage(type, signature); + return param; + } + + public List getVisited() { + return visited; + } + + List visited = new ArrayList<>(); + Stack visiting = new Stack<>(); + + /// Actual access for the inner classes as originally defined. + Map actualAccess = new HashMap<>(); + + public AsmClassVisitor() { + super(AsmConstants.API); + } + + @Override + public void visit( + int version, + int access, + String name, + String signature, + String superName, + String[] interfaces) { + var current = new ClassDecl(); + visiting.push(current); + current.binaryName = name.replace('/', '.'); + current.modifiers = TypeUtils.access(actualAccess.getOrDefault(current.binaryName, access)); + current.declKind = TypeUtils.declKind(access); + current.superclass = TypeUtils.typeUsage(Type.getObjectType(superName), null); + current.interfaces = + StreamUtil.map(interfaces, i -> TypeUtils.typeUsage(Type.getObjectType(i), null)); + if (signature != null) { + var reader = new SignatureReader(signature); + reader.accept(new AsmClassSignatureVisitor(current)); + } + super.visit(version, access, name, signature, superName, interfaces); + } + + @Override + public void visitInnerClass(String name, String outerName, String innerName, int access) { + var binaryName = name.replace('/', '.'); + actualAccess.put(binaryName, access); + var alreadyVisitedInnerClass = + visited.stream() + .filter(decl -> decl.binaryName.equals(binaryName)) + .collect(Collectors.toList()); + // If the order of visit is outer first inner second. + // We still want to correct the modifiers. + if (!alreadyVisitedInnerClass.isEmpty()) { + alreadyVisitedInnerClass.get(0).modifiers = TypeUtils.access(access); + } + } + + @Override + public FieldVisitor visitField( + int access, String name, String descriptor, String signature, Object value) { + if (name.contains("$")) { + return null; + } + + var field = new Field(); + field.name = name; + field.type = TypeUtils.typeUsage(Type.getType(descriptor), signature); + field.defaultValue = value; + field.modifiers = TypeUtils.access(access); + if ((access & ACC_ENUM) != 0) { + peekVisiting().values.add(name); + } + if (signature != null) { + var reader = new SignatureReader(signature); + reader.accept(new AsmTypeUsageSignatureVisitor(field.type)); + } + peekVisiting().fields.add(field); + return new AsmFieldVisitor(field); + } + + @Override + public MethodVisitor visitMethod( + int access, String name, String descriptor, String signature, String[] exceptions) { + var method = new Method(); + if (name.contains("$")) { + return null; + } + method.name = name; + method.descriptor = descriptor; + var type = Type.getType(descriptor); + var params = new ArrayList(); + var paramTypes = type.getArgumentTypes(); + var paramNames = new HashMap(); + for (var pt : paramTypes) { + var paramName = TypeUtils.defaultParamName(pt); + if (paramNames.containsKey(paramName)) { + var nth = paramNames.get(paramName); + paramNames.put(paramName, nth + 1); + paramName = paramName + nth; + } else { + paramNames.put(paramName, 1); + } + params.add(param(pt, paramName, null)); + } + method.returnType = TypeUtils.typeUsage(type.getReturnType(), signature); + method.modifiers = TypeUtils.access(access); + method.params = params; + if (signature != null) { + var reader = new SignatureReader(signature); + reader.accept(new AsmMethodSignatureVisitor(method)); + } + peekVisiting().methods.add(method); + return new AsmMethodVisitor(method); + } + + @Override + public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) { + if (descriptor.equals("Lkotlin/Metadata;")) { + return new KotlinMetadataAnnotationVisitor(peekVisiting()); + } + return super.visitAnnotation(descriptor, visible); + } + + @Override + public void addAnnotation(JavaAnnotation annotation) { + peekVisiting().annotations.add(annotation); + } + + @Override + public AnnotationVisitor visitAnnotationDefault(String descriptor, boolean visible) { + return super.visitAnnotation(descriptor, visible); + } + + @Override + public AnnotationVisitor visitTypeAnnotation( + int typeRef, TypePath typePath, String descriptor, boolean visible) { + return super.visitTypeAnnotation(typeRef, typePath, descriptor, visible); + } + + @Override + public void visitEnd() { + visited.add(popVisiting()); + } + + private ClassDecl peekVisiting() { + try { + return visiting.peek(); + } catch (EmptyStackException e) { + throw new SkipException("Error: stack was empty when visitEnd was called."); + } + } + + private ClassDecl popVisiting() { + try { + return visiting.pop(); + } catch (EmptyStackException e) { + throw new SkipException("Error: stack was empty when visitEnd was called."); + } + } +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/AsmConstants.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/AsmConstants.java new file mode 100644 index 000000000..e3d816510 --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/AsmConstants.java @@ -0,0 +1,11 @@ +// 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.disasm; + +import static org.objectweb.asm.Opcodes.ASM9; + +public class AsmConstants { + static final int API = ASM9; +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/AsmFieldVisitor.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/AsmFieldVisitor.java new file mode 100644 index 000000000..eb72302ab --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/AsmFieldVisitor.java @@ -0,0 +1,29 @@ +// 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.disasm; + +import com.github.dart_lang.jnigen.apisummarizer.elements.Field; +import com.github.dart_lang.jnigen.apisummarizer.elements.JavaAnnotation; +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.FieldVisitor; + +public class AsmFieldVisitor extends FieldVisitor implements AsmAnnotatedElementVisitor { + Field field; + + public AsmFieldVisitor(Field field) { + super(AsmConstants.API); + this.field = field; + } + + @Override + public void addAnnotation(JavaAnnotation annotation) { + field.annotations.add(annotation); + } + + @Override + public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) { + return AsmAnnotatedElementVisitor.super.visitAnnotationDefault(descriptor, visible); + } +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/AsmMethodSignatureVisitor.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/AsmMethodSignatureVisitor.java new file mode 100644 index 000000000..5410acfa1 --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/AsmMethodSignatureVisitor.java @@ -0,0 +1,71 @@ +// 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.disasm; + +import com.github.dart_lang.jnigen.apisummarizer.elements.Method; +import com.github.dart_lang.jnigen.apisummarizer.elements.TypeParam; +import com.github.dart_lang.jnigen.apisummarizer.elements.TypeUsage; +import java.util.ArrayList; +import java.util.List; +import org.objectweb.asm.signature.SignatureVisitor; + +public class AsmMethodSignatureVisitor extends SignatureVisitor { + private final Method method; + private final List paramTypes = new ArrayList<>(); + + public AsmMethodSignatureVisitor(Method method) { + super(AsmConstants.API); + this.method = method; + } + + @Override + public void visitFormalTypeParameter(String name) { + var typeParam = new TypeParam(); + typeParam.name = name; + method.typeParams.add(typeParam); + } + + @Override + public SignatureVisitor visitClassBound() { + var typeUsage = new TypeUsage(); + // Method initially has no type parameters. In visitFormalTypeParameter we add them + // and sequentially visitClassBound and visitInterfaceBound. + method.typeParams.get(method.typeParams.size() - 1).bounds.add(typeUsage); + return new AsmTypeUsageSignatureVisitor(typeUsage); + } + + @Override + public SignatureVisitor visitInterfaceBound() { + var typeUsage = new TypeUsage(); + method.typeParams.get(method.typeParams.size() - 1).bounds.add(typeUsage); + return new AsmTypeUsageSignatureVisitor(typeUsage); + } + + @Override + public SignatureVisitor visitReturnType() { + // Visiting params finished. + // + // In case of non-static inner class constructor, there is an extra parent parameter + // at the beginning which is not accounted for by the signature. So we fill the types + // for the last [paramTypes.size()] params. + int startIndex = method.params.size() - paramTypes.size(); + for (int i = 0; i < paramTypes.size(); ++i) { + method.params.get(startIndex + i).type = paramTypes.get(i); + } + return new AsmTypeUsageSignatureVisitor(method.returnType); + } + + @Override + public SignatureVisitor visitParameterType() { + paramTypes.add(new TypeUsage()); + return new AsmTypeUsageSignatureVisitor(paramTypes.get(paramTypes.size() - 1)); + } + + @Override + public SignatureVisitor visitExceptionType() { + // Do nothing. + return new AsmTypeUsageSignatureVisitor(new TypeUsage()); + } +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/AsmMethodVisitor.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/AsmMethodVisitor.java new file mode 100644 index 000000000..6d66fd6d6 --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/AsmMethodVisitor.java @@ -0,0 +1,61 @@ +// 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.disasm; + +import com.github.dart_lang.jnigen.apisummarizer.elements.JavaAnnotation; +import com.github.dart_lang.jnigen.apisummarizer.elements.Method; +import java.util.ArrayList; +import java.util.List; +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.TypePath; + +public class AsmMethodVisitor extends MethodVisitor implements AsmAnnotatedElementVisitor { + Method method; + List paramNames = new ArrayList<>(); + + protected AsmMethodVisitor(Method method) { + super(AsmConstants.API); + this.method = method; + } + + @Override + public void visitParameter(String name, int access) { + paramNames.add(name); + } + + @Override + public void addAnnotation(JavaAnnotation annotation) { + method.annotations.add(annotation); + } + + @Override + public AnnotationVisitor visitAnnotationDefault(String descriptor, boolean visible) { + return AsmAnnotatedElementVisitor.super.visitAnnotationDefault(descriptor, visible); + } + + @Override + public AnnotationVisitor visitTypeAnnotation( + int typeRef, TypePath typePath, String descriptor, boolean visible) { + // TODO(#23): Collect annotation on type parameter + return super.visitTypeAnnotation(typeRef, typePath, descriptor, visible); + } + + @Override + public AnnotationVisitor visitParameterAnnotation( + int parameter, String descriptor, boolean visible) { + // TODO(#23): collect and attach it to parameters + return super.visitParameterAnnotation(parameter, descriptor, visible); + } + + @Override + public void visitEnd() { + if (paramNames.size() == method.params.size()) { + for (int i = 0; i < paramNames.size(); i++) { + method.params.get(i).name = paramNames.get(i); + } + } + } +} 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 new file mode 100644 index 000000000..485c44268 --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/AsmSummarizer.java @@ -0,0 +1,26 @@ +// 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.disasm; + +import static com.github.dart_lang.jnigen.apisummarizer.util.ExceptionUtil.wrapCheckedException; + +import com.github.dart_lang.jnigen.apisummarizer.elements.ClassDecl; +import com.github.dart_lang.jnigen.apisummarizer.util.InputStreamProvider; +import java.util.List; +import org.objectweb.asm.ClassReader; + +public class AsmSummarizer { + + public static List run(List inputProviders) { + var visitor = new AsmClassVisitor(); + for (var provider : inputProviders) { + var inputStream = provider.getInputStream(); + var classReader = wrapCheckedException(ClassReader::new, inputStream); + classReader.accept(visitor, 0); + provider.close(); + } + return visitor.getVisited(); + } +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/AsmTypeUsageSignatureVisitor.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/AsmTypeUsageSignatureVisitor.java new file mode 100644 index 000000000..6ddda4546 --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/AsmTypeUsageSignatureVisitor.java @@ -0,0 +1,100 @@ +// 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.disasm; + +import com.github.dart_lang.jnigen.apisummarizer.elements.TypeUsage; +import java.util.ArrayList; +import org.objectweb.asm.signature.SignatureVisitor; + +public class AsmTypeUsageSignatureVisitor extends SignatureVisitor { + private final TypeUsage typeUsage; + + public AsmTypeUsageSignatureVisitor(TypeUsage typeUsage) { + super(AsmConstants.API); + this.typeUsage = typeUsage; + } + + @Override + public void visitBaseType(char descriptor) { + typeUsage.kind = TypeUsage.Kind.PRIMITIVE; + var name = ""; + switch (descriptor) { + case 'Z': + name = "boolean"; + break; + case 'B': + name = "byte"; + break; + case 'C': + name = "char"; + break; + case 'D': + name = "double"; + break; + case 'F': + name = "float"; + break; + case 'I': + name = "int"; + break; + case 'J': + name = "long"; + break; + case 'L': + name = "object"; + break; + case 'S': + name = "short"; + break; + case 'V': + name = "void"; + break; + } + typeUsage.shorthand = name; + typeUsage.type = new TypeUsage.PrimitiveType(name); + } + + @Override + public SignatureVisitor visitArrayType() { + typeUsage.kind = TypeUsage.Kind.ARRAY; + typeUsage.shorthand = "java.lang.Object[]"; + var elementType = new TypeUsage(); + typeUsage.type = new TypeUsage.Array(elementType); + return new AsmTypeUsageSignatureVisitor(elementType); + } + + @Override + public void visitTypeVariable(String name) { + typeUsage.kind = TypeUsage.Kind.TYPE_VARIABLE; + typeUsage.shorthand = name; + typeUsage.type = new TypeUsage.TypeVar(name); + } + + @Override + public void visitClassType(String name) { + typeUsage.kind = TypeUsage.Kind.DECLARED; + typeUsage.shorthand = name.substring(0, name.length()).replace('/', '.'); + var components = name.split("[/$]"); + var simpleName = components[components.length - 1]; + typeUsage.type = new TypeUsage.DeclaredType(typeUsage.shorthand, simpleName, new ArrayList<>()); + } + + @Override + public SignatureVisitor visitTypeArgument(char wildcard) { + // TODO(#141) support wildcards + // TODO(#144) support extend/super clauses + assert (typeUsage.type instanceof TypeUsage.DeclaredType); + var typeArg = new TypeUsage(); + ((TypeUsage.DeclaredType) typeUsage.type).params.add(typeArg); + return new AsmTypeUsageSignatureVisitor(typeArg); + } + + @Override + public void visitInnerClassType(String name) { + typeUsage.shorthand += "." + name; + ((TypeUsage.DeclaredType) typeUsage.type).binaryName += "$" + name; + ((TypeUsage.DeclaredType) typeUsage.type).simpleName = name; + } +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/KotlinMetadataAnnotationVisitor.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/KotlinMetadataAnnotationVisitor.java new file mode 100644 index 000000000..c4aa8a13b --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/KotlinMetadataAnnotationVisitor.java @@ -0,0 +1,105 @@ +// Copyright (c) 2023, 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.disasm; + +import com.github.dart_lang.jnigen.apisummarizer.elements.ClassDecl; +import com.github.dart_lang.jnigen.apisummarizer.elements.KotlinClass; +import java.util.ArrayList; +import java.util.List; +import kotlinx.metadata.jvm.KotlinClassHeader; +import kotlinx.metadata.jvm.KotlinClassMetadata; +import org.objectweb.asm.AnnotationVisitor; + +/** + * The format of Kotlin's metadata can be found here: + * https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-metadata/ + */ +public class KotlinMetadataAnnotationVisitor extends AnnotationVisitor { + private ClassDecl decl; + + private int kind; + private int[] metadataVersion; + private List data1 = new ArrayList<>(); + private List data2 = new ArrayList<>(); + private String extraString; + private String packageName; + private int extraInt; + + public KotlinMetadataAnnotationVisitor(ClassDecl decl) { + super(AsmConstants.API); + this.decl = decl; + } + + @Override + public void visit(String name, Object value) { + switch (name) { + case "k": + kind = (int) value; + return; + case "mv": + metadataVersion = (int[]) value; + return; + case "xs": + extraString = (String) value; + return; + case "pn": + packageName = (String) value; + return; + case "xi": + extraInt = (int) value; + } + } + + @Override + public AnnotationVisitor visitArray(String name) { + List arr; + switch (name) { + case "d1": + arr = data1; + break; + case "d2": + arr = data2; + break; + default: + return super.visitArray(name); + } + return new AnnotationVisitor(AsmConstants.API) { + @Override + public void visit(String name, Object value) { + arr.add((String) value); + super.visit(name, value); + } + }; + } + + @Override + public void visitEnd() { + var header = + new KotlinClassHeader( + kind, + metadataVersion, + data1.toArray(String[]::new), + data2.toArray(String[]::new), + extraString, + packageName, + extraInt); + var metadata = KotlinClassMetadata.read(header); + if (metadata instanceof KotlinClassMetadata.Class) { + decl.kotlinClass = + KotlinClass.fromKmClass(((KotlinClassMetadata.Class) metadata).toKmClass()); + } else if (metadata instanceof KotlinClassMetadata.FileFacade) { + // TODO(#301): Handle file facades. + } else if (metadata instanceof KotlinClassMetadata.SyntheticClass) { + // Ignore synthetic classes such as lambdas. + } else if (metadata instanceof KotlinClassMetadata.MultiFileClassFacade) { + // Ignore multi-file classes + } else if (metadata instanceof KotlinClassMetadata.MultiFileClassPart) { + // Ignore multi-file classes + } else if (metadata instanceof KotlinClassMetadata.Unknown) { + // Unsupported + } + super.visitEnd(); + } +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/TypeUtils.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/TypeUtils.java new file mode 100644 index 000000000..8f1856523 --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/TypeUtils.java @@ -0,0 +1,106 @@ +// 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.disasm; + +import static org.objectweb.asm.Opcodes.*; +import static org.objectweb.asm.Type.ARRAY; +import static org.objectweb.asm.Type.OBJECT; + +import com.github.dart_lang.jnigen.apisummarizer.elements.DeclKind; +import com.github.dart_lang.jnigen.apisummarizer.elements.TypeUsage; +import com.github.dart_lang.jnigen.apisummarizer.util.SkipException; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import org.objectweb.asm.Type; + +class TypeUtils { + + public static String simpleName(Type type) { + var internalName = type.getInternalName(); + if (type.getInternalName().length() == 1) { + return type.getClassName(); + } + var components = internalName.split("[/$]"); + if (components.length == 0) { + throw new SkipException("Cannot derive simple name: " + internalName); + } + return components[components.length - 1]; + } + + public static TypeUsage typeUsage(Type type, @SuppressWarnings("unused") String signature) { + var usage = new TypeUsage(); + usage.shorthand = type.getClassName(); + switch (type.getSort()) { + case OBJECT: + usage.kind = TypeUsage.Kind.DECLARED; + usage.type = + new TypeUsage.DeclaredType( + type.getInternalName().replace('/', '.'), TypeUtils.simpleName(type), null); + break; + case ARRAY: + usage.kind = TypeUsage.Kind.ARRAY; + usage.type = new TypeUsage.Array(TypeUtils.typeUsage(type.getElementType(), null)); + break; + default: + usage.kind = TypeUsage.Kind.PRIMITIVE; + usage.type = new TypeUsage.PrimitiveType(type.getClassName()); + } + // TODO(#23): generics + return usage; + } + + public static Set access(int access) { + var result = new HashSet(); + for (var ac : acc.entrySet()) { + if ((ac.getValue() & access) != 0) { + result.add(ac.getKey()); + } + } + return result; + } + + private static final Map acc = new HashMap<>(); + + static { + acc.put("static", ACC_STATIC); + acc.put("private", ACC_PRIVATE); + acc.put("protected", ACC_PROTECTED); + acc.put("public", ACC_PUBLIC); + acc.put("abstract", ACC_ABSTRACT); + acc.put("final", ACC_FINAL); + acc.put("native", ACC_NATIVE); + } + + static DeclKind declKind(int access) { + if ((access & ACC_ENUM) != 0) return DeclKind.ENUM; + if ((access & ACC_INTERFACE) != 0) return DeclKind.INTERFACE; + if ((access & ACC_ANNOTATION) != 0) return DeclKind.ANNOTATION_TYPE; + return DeclKind.CLASS; + } + + static String defaultParamName(Type type) { + switch (type.getSort()) { + case ARRAY: + return defaultParamName(type.getElementType()) + 's'; + case OBJECT: + return unCapitalize(simpleName(type)); + case Type.METHOD: + throw new SkipException("unexpected method type" + type); + default: // Primitive type + var typeCh = type.getInternalName().charAt(0); + return String.valueOf(Character.toLowerCase(typeCh)); + } + } + + private static String unCapitalize(String s) { + var first = Character.toLowerCase(s.charAt(0)); + if (s.length() == 1) { + return String.valueOf(first); + } + return first + s.substring(1); + } +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/doclet/AnnotationVisitor.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/doclet/AnnotationVisitor.java new file mode 100644 index 000000000..f5343eec0 --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/doclet/AnnotationVisitor.java @@ -0,0 +1,100 @@ +// 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 java.util.List; +import java.util.stream.Collectors; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.AnnotationValue; +import javax.lang.model.element.AnnotationValueVisitor; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; + +public class AnnotationVisitor implements AnnotationValueVisitor { + private final ElementBuilders builders; + AstEnv env; + + public AnnotationVisitor(ElementBuilders builders) { + this.builders = builders; + this.env = builders.env; + } + + @Override + public Object visit(AnnotationValue annotationValue, Void unused) { + return null; + } + + @Override + public Object visitBoolean(boolean b, Void unused) { + return b; + } + + @Override + public Object visitByte(byte b, Void unused) { + return b; + } + + @Override + public Object visitChar(char c, Void unused) { + return c; + } + + @Override + public Object visitDouble(double v, Void unused) { + return v; + } + + @Override + public Object visitFloat(float v, Void unused) { + return v; + } + + @Override + public Object visitInt(int i, Void unused) { + return i; + } + + @Override + public Object visitLong(long l, Void unused) { + return l; + } + + @Override + public Object visitShort(short i, Void unused) { + return i; + } + + @Override + public Object visitString(String s, Void unused) { + return s; + } + + @Override + public Object visitType(TypeMirror typeMirror, Void unused) { + return builders.typeUsage(typeMirror); + } + + @Override + public Object visitEnumConstant(VariableElement variableElement, Void unused) { + // TODO(#23): Perhaps simple name is not enough. We need to return qualified + // name + enum constant name for completeness. + return variableElement.getSimpleName(); + } + + @Override + public Object visitAnnotation(AnnotationMirror mirror, Void unused) { + return builders.annotation(mirror); + } + + @Override + public Object visitArray(List list, Void unused) { + return list.stream().map(x -> x.accept(this, null)).collect(Collectors.toList()); + } + + @Override + public Object visitUnknown(AnnotationValue annotationValue, Void unused) { + return null; + } +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/doclet/AstEnv.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/doclet/AstEnv.java new file mode 100644 index 000000000..71e31c4cc --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/doclet/AstEnv.java @@ -0,0 +1,27 @@ +// 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.sun.source.util.DocTrees; +import javax.lang.model.util.Elements; +import javax.lang.model.util.Types; +import jdk.javadoc.doclet.DocletEnvironment; + +/** Class to hold utility classes initialized from DocletEnvironment. */ +public class AstEnv { + public final Types types; + public final Elements elements; + public final DocTrees trees; + + public AstEnv(Types types, Elements elements, DocTrees trees) { + this.types = types; + this.elements = elements; + this.trees = trees; + } + + public static AstEnv fromEnvironment(DocletEnvironment env) { + return new AstEnv(env.getTypeUtils(), env.getElementUtils(), env.getDocTrees()); + } +} 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 new file mode 100644 index 000000000..675da7b8a --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/doclet/ElementBuilders.java @@ -0,0 +1,204 @@ +// 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.*; +import com.github.dart_lang.jnigen.apisummarizer.util.StreamUtil; +import com.sun.source.doctree.DocCommentTree; +import java.util.HashMap; +import java.util.List; +import java.util.stream.Collectors; +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +public class ElementBuilders { + AstEnv env; + + public ElementBuilders(AstEnv env) { + this.env = env; + } + + private void fillInFromTypeElement(TypeElement e, ClassDecl c) { + c.modifiers = e.getModifiers().stream().map(Modifier::toString).collect(Collectors.toSet()); + c.binaryName = env.elements.getBinaryName(e).toString(); + switch (e.getKind()) { + case INTERFACE: + c.declKind = DeclKind.INTERFACE; + break; + case CLASS: + c.declKind = DeclKind.CLASS; + break; + case ENUM: + c.declKind = DeclKind.ENUM; + break; + case ANNOTATION_TYPE: + c.declKind = DeclKind.ANNOTATION_TYPE; + break; + default: + throw new RuntimeException( + "Unexpected element kind " + e.getKind() + " on " + c.binaryName); + } + c.javadoc = docComment(env.trees.getDocCommentTree(e)); + c.typeParams = StreamUtil.map(e.getTypeParameters(), this::typeParam); + var superclass = e.getSuperclass(); + if (superclass instanceof DeclaredType) { + c.superclass = typeUsage(superclass); + } + c.annotations = StreamUtil.map(e.getAnnotationMirrors(), this::annotation); + c.interfaces = StreamUtil.map(e.getInterfaces(), this::typeUsage); + } + + public ClassDecl classDecl(TypeElement e) { + var c = new ClassDecl(); + fillInFromTypeElement(e, c); + return c; + } + + public Field field(VariableElement e) { + assert e.getKind() == ElementKind.FIELD; + var field = new Field(); + field.name = e.getSimpleName().toString(); + field.modifiers = e.getModifiers().stream().map(Modifier::toString).collect(Collectors.toSet()); + field.defaultValue = e.getConstantValue(); + if (field.defaultValue instanceof Character) { + field.defaultValue = (int) (Character) field.defaultValue; + } + field.type = typeUsage(e.asType()); + field.javadoc = docComment(env.trees.getDocCommentTree(e)); + field.annotations = annotations(e.getAnnotationMirrors()); + return field; + } + + public List annotations(List mirrors) { + return mirrors.stream().map(this::annotation).collect(Collectors.toList()); + } + + public JavaAnnotation annotation(AnnotationMirror mirror) { + var annotation = new JavaAnnotation(); + var type = mirror.getAnnotationType(); + var typeElement = (TypeElement) (env.types.asElement(type)); + annotation.binaryName = env.elements.getBinaryName(typeElement).toString(); + var values = env.elements.getElementValuesWithDefaults(mirror); + if (values.isEmpty()) { + return annotation; + } + + // This is not perfect, but some metadata is better than none. + annotation.properties = new HashMap<>(); + for (var key : values.keySet()) { + var val = values.get(key); + var obj = val.getValue(); + // TODO(#23): Accurately represent more complex annotation values + if (obj instanceof Number) { + annotation.properties.put(key.getSimpleName().toString(), obj); + } else { + annotation.properties.put(key.getSimpleName().toString(), obj.toString()); + } + } + return annotation; + } + + public JavaDocComment docComment(DocCommentTree tree) { + if (tree == null) { + return null; + } + return new JavaDocComment(tree.toString()); + } + + public TypeParam typeParam(TypeParameterElement tpe) { + var tp = new TypeParam(); + tp.name = tpe.getSimpleName().toString(); + tp.bounds = tpe.getBounds().stream().map(this::typeUsage).collect(Collectors.toList()); + return tp; + } + + public Param param(VariableElement e) { + var param = new Param(); + param.javadoc = docComment(env.trees.getDocCommentTree(e)); + param.name = e.getSimpleName().toString(); + param.type = typeUsage(e.asType()); + param.annotations = annotations(e.getAnnotationMirrors()); + return param; + } + + public TypeUsage typeUsage(TypeMirror type) { + var u = new TypeUsage(); + u.shorthand = type.toString(); + var element = env.types.asElement(type); + switch (type.getKind()) { + case DECLARED: + // Unique name that's binary name not qualified name + // (It's somewhat confusing but qualified name does not need to be unique, + // because of nesting) + u.kind = TypeUsage.Kind.DECLARED; + var name = + element instanceof TypeElement + ? env.elements.getBinaryName((TypeElement) element).toString() + : element.getSimpleName().toString(); + List params = null; + if (type instanceof DeclaredType) { // it will be + params = + ((DeclaredType) type) + .getTypeArguments().stream().map(this::typeUsage).collect(Collectors.toList()); + } + u.type = new TypeUsage.DeclaredType(name, element.getSimpleName().toString(), params); + break; + case TYPEVAR: + u.kind = TypeUsage.Kind.TYPE_VARIABLE; + // TODO(#23): Encode bounds of type variable. + // A straightforward approach will cause infinite recursion very + // easily. Another approach I can think of is only encoding the + // erasure of the type variable per JLS. + u.type = new TypeUsage.TypeVar(element.getSimpleName().toString()); + break; + case ARRAY: + u.kind = TypeUsage.Kind.ARRAY; + var arr = ((ArrayType) type); + u.type = new TypeUsage.Array(typeUsage(arr.getComponentType())); + break; + case VOID: + u.type = new TypeUsage.PrimitiveType("void"); + u.kind = TypeUsage.Kind.PRIMITIVE; + break; + case WILDCARD: + u.kind = TypeUsage.Kind.WILDCARD; + var wildcard = ((WildcardType) type); + var extendsBound = wildcard.getExtendsBound(); + var superBound = wildcard.getSuperBound(); + u.type = + new TypeUsage.Wildcard( + extendsBound != null ? typeUsage(extendsBound) : null, + superBound != null ? typeUsage(superBound) : null); + break; + case INTERSECTION: + u.kind = TypeUsage.Kind.INTERSECTION; + u.type = + new TypeUsage.Intersection( + ((IntersectionType) type) + .getBounds().stream().map(this::typeUsage).collect(Collectors.toList())); + break; + default: + u.kind = TypeUsage.Kind.PRIMITIVE; + if (type instanceof PrimitiveType) { + u.type = new TypeUsage.PrimitiveType(type.toString()); + } else { + System.out.println("Unsupported type: " + type); + // throw exception. + } + } + return u; + } + + public Method method(ExecutableElement e) { + var m = new Method(); + m.name = e.getSimpleName().toString(); + m.modifiers = e.getModifiers().stream().map(Modifier::toString).collect(Collectors.toSet()); + m.typeParams = e.getTypeParameters().stream().map(this::typeParam).collect(Collectors.toList()); + m.returnType = typeUsage(e.getReturnType()); + m.javadoc = docComment(env.trees.getDocCommentTree(e)); + m.annotations = annotations(e.getAnnotationMirrors()); + return m; + } +} 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 new file mode 100644 index 000000000..abbc7cc65 --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/doclet/SummarizerDoclet.java @@ -0,0 +1,165 @@ +// 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 SummarizerDoclet implements Doclet { + private AstEnv utils; + + @Override + public void init(Locale locale, Reporter reporter) {} + + @Override + public String getName() { + return "ApiSummarizer"; + } + + @Override + public Set getSupportedOptions() { + return Collections.emptySet(); + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.RELEASE_11; + } + + public static List getClasses() { + return classes; + } + + public static List classes; + + @Override + public boolean run(DocletEnvironment docletEnvironment) { + Log.info("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 packages = new Stack<>(); + Stack types = new Stack<>(); + Method method; + } + + public class SummarizingScanner extends ElementScanner9 { + List packages = new ArrayList<>(); + List 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.info("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.info("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.info("Skip type: %s", e.getQualifiedName()); + } + break; + case ANNOTATION_TYPE: + Log.info("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.info("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/elements/ClassDecl.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/ClassDecl.java new file mode 100644 index 000000000..746b91378 --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/ClassDecl.java @@ -0,0 +1,43 @@ +// 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.elements; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * A class or interface declaration. + * + *

Here's an example for various kinds of names stored in this structure: { simpleName : + * "Example", binaryName : "dev.dart.sample.Example", parentName : null, packageName : + * "dev.dart.sample", } + */ +public class ClassDecl { + public DeclKind declKind; + + /** Modifiers eg: static, public and abstract. */ + public Set modifiers; + + /** + * Unique, fully qualified name of the class, it's like a qualified name used in a program but + * uses $ instead of dot (.) before nested classes. + */ + public String binaryName; + + public List typeParams = new ArrayList<>(); + public List methods = new ArrayList<>(); + public List fields = new ArrayList<>(); + public TypeUsage superclass; + public List interfaces = new ArrayList<>(); + public boolean hasStaticInit; + public boolean hasInstanceInit; + public JavaDocComment javadoc; + public List annotations; + public KotlinClass kotlinClass; + + /** In case of enum, names of enum constants */ + public List values = new ArrayList<>(); +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/DeclKind.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/DeclKind.java new file mode 100644 index 000000000..e2e533ec2 --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/DeclKind.java @@ -0,0 +1,12 @@ +// 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.elements; + +public enum DeclKind { + CLASS, + ENUM, + INTERFACE, + ANNOTATION_TYPE +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/Field.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/Field.java new file mode 100644 index 000000000..ced5ceafe --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/Field.java @@ -0,0 +1,20 @@ +// 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.elements; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class Field { + public Set modifiers = new HashSet<>(); + public String name; + public TypeUsage type; + public Object defaultValue; + + public JavaDocComment javadoc; + public List annotations = new ArrayList<>(); +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/JavaAnnotation.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/JavaAnnotation.java new file mode 100644 index 000000000..c463cba55 --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/JavaAnnotation.java @@ -0,0 +1,23 @@ +// 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.elements; + +import java.util.HashMap; +import java.util.Map; + +public class JavaAnnotation { + public String binaryName; + public Map properties = new HashMap<>(); + + public static class EnumVal { + public String enumClass; + public String value; + + public EnumVal(String enumClass, String value) { + this.enumClass = enumClass; + this.value = value; + } + } +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/JavaDocComment.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/JavaDocComment.java new file mode 100644 index 000000000..c882c97af --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/JavaDocComment.java @@ -0,0 +1,15 @@ +// 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.elements; + +public class JavaDocComment { + // TODO(#28): Build a detailed tree representation of JavaDocComment + // which can be processed by tools in other languages as well. + public String comment; + + public JavaDocComment(String comment) { + this.comment = comment; + } +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/KotlinClass.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/KotlinClass.java new file mode 100644 index 000000000..22906f705 --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/KotlinClass.java @@ -0,0 +1,62 @@ +// Copyright (c) 2023, 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.elements; + +import java.util.List; +import java.util.stream.Collectors; +import kotlinx.metadata.KmClass; +import kotlinx.metadata.jvm.JvmExtensionsKt; + +public class KotlinClass { + public String name; + public String moduleName; + public List functions; + public List properties; + public List constructors; + public List typeParameters; + public List contextReceiverTypes; + public List superTypes; + public List nestedClasses; + public List enumEntries; + public List sealedClasses; + public String companionObject; + public String inlineClassUnderlyingPropertyName; + public KotlinType inlineClassUnderlyingType; + public int flags; + public int jvmFlags; + + public static KotlinClass fromKmClass(KmClass c) { + var klass = new KotlinClass(); + klass.name = c.getName(); + klass.moduleName = JvmExtensionsKt.getModuleName(c); + klass.functions = + c.getFunctions().stream().map(KotlinFunction::fromKmFunction).collect(Collectors.toList()); + klass.properties = + c.getProperties().stream().map(KotlinProperty::fromKmProperty).collect(Collectors.toList()); + klass.constructors = + c.getConstructors().stream() + .map(KotlinConstructor::fromKmConstructor) + .collect(Collectors.toList()); + klass.typeParameters = + c.getTypeParameters().stream() + .map(KotlinTypeParameter::fromKmTypeParameter) + .collect(Collectors.toList()); + klass.contextReceiverTypes = + c.getContextReceiverTypes().stream() + .map(KotlinType::fromKmType) + .collect(Collectors.toList()); + klass.superTypes = + c.getSupertypes().stream().map(KotlinType::fromKmType).collect(Collectors.toList()); + klass.enumEntries = c.getEnumEntries(); + klass.flags = c.getFlags(); + klass.jvmFlags = JvmExtensionsKt.getJvmFlags(c); + klass.nestedClasses = c.getNestedClasses(); + klass.companionObject = c.getCompanionObject(); + klass.inlineClassUnderlyingPropertyName = c.getInlineClassUnderlyingPropertyName(); + klass.inlineClassUnderlyingType = KotlinType.fromKmType(c.getInlineClassUnderlyingType()); + klass.sealedClasses = c.getSealedSubclasses(); + return klass; + } +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/KotlinConstructor.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/KotlinConstructor.java new file mode 100644 index 000000000..dae3a2f61 --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/KotlinConstructor.java @@ -0,0 +1,30 @@ +// Copyright (c) 2023, 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.elements; + +import java.util.List; +import java.util.stream.Collectors; +import kotlinx.metadata.KmConstructor; +import kotlinx.metadata.jvm.JvmExtensionsKt; + +public class KotlinConstructor { + public String name; + public String descriptor; + public List valueParameters; + public int flags; + + public static KotlinConstructor fromKmConstructor(KmConstructor c) { + var ctor = new KotlinConstructor(); + ctor.flags = c.getFlags(); + var signature = JvmExtensionsKt.getSignature(c); + ctor.name = signature == null ? null : signature.getName(); + ctor.descriptor = signature == null ? null : signature.getDesc(); + ctor.valueParameters = + c.getValueParameters().stream() + .map(KotlinValueParameter::fromKmValueParameter) + .collect(Collectors.toList()); + return ctor; + } +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/KotlinFunction.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/KotlinFunction.java new file mode 100644 index 000000000..87cdc7be8 --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/KotlinFunction.java @@ -0,0 +1,55 @@ +// Copyright (c) 2023, 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.elements; + +import java.util.List; +import java.util.stream.Collectors; +import kotlinx.metadata.Flag; +import kotlinx.metadata.KmFunction; +import kotlinx.metadata.jvm.JvmExtensionsKt; + +public class KotlinFunction { + /** Name in the byte code. */ + public String name; + + public String descriptor; + + /** Name in the Kotlin's metadata. */ + public String kotlinName; + + public List valueParameters; + public KotlinType returnType; + public KotlinType receiverParameterType; + public List contextReceiverTypes; + public List typeParameters; + public int flags; + public boolean isSuspend; + + public static KotlinFunction fromKmFunction(KmFunction f) { + var fun = new KotlinFunction(); + var signature = JvmExtensionsKt.getSignature(f); + fun.descriptor = signature == null ? null : signature.getDesc(); + fun.name = signature == null ? null : signature.getName(); + fun.kotlinName = f.getName(); + fun.flags = f.getFlags(); + // Processing the information needed from the flags. + fun.isSuspend = Flag.Function.IS_SUSPEND.invoke(fun.flags); + fun.valueParameters = + f.getValueParameters().stream() + .map(KotlinValueParameter::fromKmValueParameter) + .collect(Collectors.toList()); + fun.returnType = KotlinType.fromKmType(f.getReturnType()); + fun.receiverParameterType = KotlinType.fromKmType(f.getReceiverParameterType()); + fun.contextReceiverTypes = + f.getContextReceiverTypes().stream() + .map(KotlinType::fromKmType) + .collect(Collectors.toList()); + fun.typeParameters = + f.getTypeParameters().stream() + .map(KotlinTypeParameter::fromKmTypeParameter) + .collect(Collectors.toList()); + return fun; + } +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/KotlinProperty.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/KotlinProperty.java new file mode 100644 index 000000000..2858be4ba --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/KotlinProperty.java @@ -0,0 +1,68 @@ +// Copyright (c) 2023, 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.elements; + +import java.util.List; +import java.util.stream.Collectors; +import kotlinx.metadata.KmProperty; +import kotlinx.metadata.jvm.JvmExtensionsKt; + +public class KotlinProperty { + public String fieldName; + public String fieldDescriptor; + + /** Getter's name in the byte code. */ + public String getterName; + + public String getterDescriptor; + + /** Setter's name in the byte code. */ + public String setterName; + + public String setterDescriptor; + + /** Name in the Kotlin's metadata. */ + public String kotlinName; + + public KotlinType returnType; + public KotlinType receiverParameterType; + public List contextReceiverTypes; + public int jvmFlags; + public int flags; + public int setterFlags; + public int getterFlags; + public List typeParameters; + public KotlinValueParameter setterParameter; + + public static KotlinProperty fromKmProperty(KmProperty p) { + var prop = new KotlinProperty(); + var fieldSignature = JvmExtensionsKt.getFieldSignature(p); + prop.fieldDescriptor = fieldSignature == null ? null : fieldSignature.getDesc(); + prop.fieldName = fieldSignature == null ? null : fieldSignature.getName(); + var getterSignature = JvmExtensionsKt.getGetterSignature(p); + prop.getterDescriptor = getterSignature == null ? null : getterSignature.getDesc(); + prop.getterName = getterSignature == null ? null : getterSignature.getName(); + var setterSignature = JvmExtensionsKt.getSetterSignature(p); + prop.setterDescriptor = setterSignature == null ? null : setterSignature.getDesc(); + prop.setterName = setterSignature == null ? null : setterSignature.getName(); + prop.kotlinName = p.getName(); + prop.returnType = KotlinType.fromKmType(p.getReturnType()); + prop.receiverParameterType = KotlinType.fromKmType(p.getReceiverParameterType()); + prop.contextReceiverTypes = + p.getContextReceiverTypes().stream() + .map(KotlinType::fromKmType) + .collect(Collectors.toList()); + prop.jvmFlags = JvmExtensionsKt.getJvmFlags(p); + prop.flags = p.getFlags(); + prop.setterFlags = p.getSetterFlags(); + prop.getterFlags = p.getGetterFlags(); + prop.typeParameters = + p.getTypeParameters().stream() + .map(KotlinTypeParameter::fromKmTypeParameter) + .collect(Collectors.toList()); + prop.setterParameter = KotlinValueParameter.fromKmValueParameter(p.getSetterParameter()); + return prop; + } +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/KotlinType.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/KotlinType.java new file mode 100644 index 000000000..8e91122ef --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/KotlinType.java @@ -0,0 +1,40 @@ +// Copyright (c) 2023, 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.elements; + +import java.util.List; +import java.util.stream.Collectors; +import kotlinx.metadata.KmClassifier; +import kotlinx.metadata.KmType; + +public class KotlinType { + public int flags; + public String kind; + public String name; + public int id; + public List arguments; + + public static KotlinType fromKmType(KmType t) { + if (t == null) return null; + var type = new KotlinType(); + type.flags = t.getFlags(); + var classifier = t.getClassifier(); + if (classifier instanceof KmClassifier.Class) { + type.kind = "class"; + type.name = ((KmClassifier.Class) classifier).getName(); + } else if (classifier instanceof KmClassifier.TypeAlias) { + type.kind = "typeAlias"; + type.name = ((KmClassifier.TypeAlias) classifier).getName(); + } else if (classifier instanceof KmClassifier.TypeParameter) { + type.kind = "typeParameter"; + type.id = ((KmClassifier.TypeParameter) classifier).getId(); + } + type.arguments = + t.getArguments().stream() + .map(KotlinTypeProjection::fromKmTypeProjection) + .collect(Collectors.toList()); + return type; + } +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/KotlinTypeParameter.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/KotlinTypeParameter.java new file mode 100644 index 000000000..449aef16c --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/KotlinTypeParameter.java @@ -0,0 +1,29 @@ +// Copyright (c) 2023, 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.elements; + +import java.util.List; +import java.util.stream.Collectors; +import kotlinx.metadata.KmTypeParameter; +import kotlinx.metadata.KmVariance; + +public class KotlinTypeParameter { + public String name; + public int id; + public int flags; + public List upperBounds; + public KmVariance variance; + + public static KotlinTypeParameter fromKmTypeParameter(KmTypeParameter t) { + var typeParam = new KotlinTypeParameter(); + typeParam.name = t.getName(); + typeParam.id = t.getId(); + typeParam.flags = t.getFlags(); + typeParam.upperBounds = + t.getUpperBounds().stream().map(KotlinType::fromKmType).collect(Collectors.toList()); + typeParam.variance = t.getVariance(); + return typeParam; + } +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/KotlinTypeProjection.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/KotlinTypeProjection.java new file mode 100644 index 000000000..364634c2e --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/KotlinTypeProjection.java @@ -0,0 +1,20 @@ +// Copyright (c) 2023, 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.elements; + +import kotlinx.metadata.KmTypeProjection; +import kotlinx.metadata.KmVariance; + +public class KotlinTypeProjection { + public KotlinType type; + public KmVariance variance; + + public static KotlinTypeProjection fromKmTypeProjection(KmTypeProjection t) { + var proj = new KotlinTypeProjection(); + proj.type = KotlinType.fromKmType(t.getType()); + proj.variance = t.getVariance(); + return proj; + } +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/KotlinValueParameter.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/KotlinValueParameter.java new file mode 100644 index 000000000..1fba28d62 --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/KotlinValueParameter.java @@ -0,0 +1,24 @@ +// Copyright (c) 2023, 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.elements; + +import kotlinx.metadata.KmValueParameter; + +public class KotlinValueParameter { + public String name; + public int flags; + public KotlinType type; + public KotlinType varargElementType; + + public static KotlinValueParameter fromKmValueParameter(KmValueParameter p) { + if (p == null) return null; + var param = new KotlinValueParameter(); + param.name = p.getName(); + param.flags = p.getFlags(); + param.type = KotlinType.fromKmType(p.getType()); + param.varargElementType = KotlinType.fromKmType(p.getVarargElementType()); + return param; + } +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/Method.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/Method.java new file mode 100644 index 000000000..33bb0fb89 --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/Method.java @@ -0,0 +1,22 @@ +// 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.elements; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class Method { + public Set modifiers = new HashSet<>(); + public String name; + public String descriptor; + public List typeParams = new ArrayList<>(); + public List params = new ArrayList<>(); + public TypeUsage returnType; + + public JavaDocComment javadoc; + public List annotations = new ArrayList<>(); +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/Package.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/Package.java new file mode 100644 index 000000000..ca2bfce9d --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/Package.java @@ -0,0 +1,9 @@ +// 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.elements; + +public class Package { + public String name; +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/Param.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/Param.java new file mode 100644 index 000000000..433f6bf3a --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/Param.java @@ -0,0 +1,16 @@ +// 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.elements; + +import java.util.ArrayList; +import java.util.List; + +public class Param { + public String name; + public TypeUsage type; + + public JavaDocComment javadoc; + public List annotations = new ArrayList<>(); +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/TypeParam.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/TypeParam.java new file mode 100644 index 000000000..8172ee6d8 --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/TypeParam.java @@ -0,0 +1,13 @@ +// 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.elements; + +import java.util.ArrayList; +import java.util.List; + +public class TypeParam { + public String name; + public List bounds = new ArrayList<>(); +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/TypeUsage.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/TypeUsage.java new file mode 100644 index 000000000..a60407caf --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/elements/TypeUsage.java @@ -0,0 +1,87 @@ +// 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.elements; + +import java.util.List; + +public class TypeUsage { + public TypeUsage(String shorthand, Kind kind, ReferredType type) { + this.shorthand = shorthand; + this.kind = kind; + this.type = type; + } + + public TypeUsage() {} + + public enum Kind { + DECLARED, + TYPE_VARIABLE, + WILDCARD, + ARRAY, + INTERSECTION, + PRIMITIVE, + } + + // Could've made it just a type hierarchy, but client code parsing JSON + // needs to know the type beforehand, before it can deserialize the `type` field. + public String shorthand; + public Kind kind; + public ReferredType type; + + public abstract static class ReferredType {} + + public static class PrimitiveType extends ReferredType { + public String name; + + public PrimitiveType(String name) { + this.name = name; + } + } + + public static class DeclaredType extends ReferredType { + public String binaryName; + public String simpleName; + public List params; + + public DeclaredType(String binaryName, String simpleName, List params) { + this.binaryName = binaryName; + this.simpleName = simpleName; + this.params = params; + } + } + + public static class TypeVar extends ReferredType { + public String name; + + public TypeVar(String name) { + this.name = name; + } + } + + public static class Wildcard extends ReferredType { + public TypeUsage extendsBound, superBound; + + public Wildcard(TypeUsage extendsBound, TypeUsage superBound) { + this.extendsBound = extendsBound; + this.superBound = superBound; + } + } + + public static class Intersection extends ReferredType { + public List types; + + public Intersection(List types) { + this.types = types; + } + } + + public static class Array extends ReferredType { + public TypeUsage type; + + public Array(TypeUsage type) { + this.type = type; + } + } +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/util/ClassFinder.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/util/ClassFinder.java new file mode 100644 index 000000000..23c1ca534 --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/util/ClassFinder.java @@ -0,0 +1,199 @@ +package com.github.dart_lang.jnigen.apisummarizer.util; + +import static com.github.dart_lang.jnigen.apisummarizer.util.ExceptionUtil.wrapCheckedException; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import javax.tools.JavaFileObject; +import javax.tools.StandardJavaFileManager; + +public class ClassFinder { + // If class is A$B$C, simpleName can be B$C or A$B$C. Doesn't matter much, because + // A can't be anonymous class. + private static boolean isNonAnonymousNestedClassName(String simpleName) { + String[] nestedParts = simpleName.split("\\$"); + return Arrays.stream(nestedParts).allMatch(part -> part.matches("[a-zA-Z_][a-zA-Z0-9_]*")); + } + + public static boolean isNestedClassOf(String pathString, String fqnWithSlashes, String suffix) { + var fqnWithSlashesDollarSign = fqnWithSlashes + "$"; + if (!pathString.startsWith(fqnWithSlashesDollarSign) || !pathString.endsWith(suffix)) { + return false; + } + String nested = + pathString.substring( + fqnWithSlashesDollarSign.length(), pathString.length() - suffix.length()); + return isNonAnonymousNestedClassName(nested); + } + + private static boolean isNonAnonymousClassFullPath(String path) { + String[] pathParts = path.split("[/\\\\]"); + String simpleNameWithExt = pathParts[pathParts.length - 1]; + int extIndex = simpleNameWithExt.indexOf('.'); + assert extIndex != -1 : "Should've passed full path with extension to this method"; + String simpleName = simpleNameWithExt.substring(0, extIndex); + return isNonAnonymousNestedClassName(simpleName); + } + + // Finds [fqn] and its children with [suffix] in [entries]. + public static Optional> findClassAndChildren( + TreeSet entries, String fqn, String sep, String suffix) { + String fqnWithSlashes = fqn.replace(".", sep); + String fqnWithSlashesSuffix = fqnWithSlashes + suffix; + String fqnWithSlashesSlash = fqnWithSlashes + sep; + String fqnWithSlashesDollarSign = fqnWithSlashes + "$"; + if (entries.contains(fqnWithSlashesSuffix)) { + List classes = new ArrayList<>(); + // Add nested classes first, because they're alphabetically first + entries.tailSet(fqnWithSlashesDollarSign).stream() + .takeWhile(entry -> entry.startsWith(fqnWithSlashesDollarSign)) + // Note: filter comes after takeWhile, because it can filter out additional elements + // eg: Class$1 - but there may be valid nested classes after Class$1. + .filter(entry -> isNestedClassOf(entry, fqnWithSlashes, suffix)) + .forEach(classes::add); + classes.add(fqnWithSlashesSuffix); + return Optional.of(classes); + } + + // consider fqnWithSlashes as a directory + List children = + entries.tailSet(fqnWithSlashesSlash).stream() + // takeWhile instead of filter - the difference is O(log n + k) instead of O(n) + // so always use takeWhile when doing a treeSet subset stream. + .takeWhile(entry -> entry.startsWith(fqnWithSlashesSlash)) + .filter(entry -> entry.endsWith(suffix)) + .filter(ClassFinder::isNonAnonymousClassFullPath) + .collect(Collectors.toList()); + return children.isEmpty() ? Optional.empty() : Optional.of(children); + } + + public static void findFilesInPath( + String searchLocation, + String suffix, + Map> classes, + Function, List> mapper) { + Path searchPath = Path.of(searchLocation); + + TreeSet filePaths; + try (var walk = Files.walk(searchPath)) { + filePaths = + walk.map(searchPath::relativize) + .map(Path::toString) + .collect(Collectors.toCollection(TreeSet::new)); + } catch (IOException e) { + throw new RuntimeException(e); + } + + for (var className : classes.keySet()) { + if (classes.get(className) != null) { // Already found by other method of searching + continue; + } + var resultPaths = findClassAndChildren(filePaths, className, File.separator, suffix); + if (resultPaths.isPresent()) { + // [filePaths] and [resultPaths] are relativized to searchPath. + // perform opposite operation (resolve) to get full paths. + var fullPaths = + resultPaths.get().stream().map(searchPath::resolve).collect(Collectors.toList()); + classes.put(className, mapper.apply(fullPaths)); + } + } + } + + public static boolean findFilesInJar( + Map> classes, + JarFile jar, + String suffix, + BiFunction, List> mapper) { + + // It appears JAR file entries are always separated by "/" + var jarSeparator = "/"; + var entryNames = + jar.stream().map(JarEntry::getName).collect(Collectors.toCollection(TreeSet::new)); + boolean foundClassesInThisJar = false; + for (var fqn : classes.keySet()) { + if (classes.get(fqn) != null) { // already found + continue; + } + var resultPaths = findClassAndChildren(entryNames, fqn, jarSeparator, suffix); + if (resultPaths.isPresent()) { + var jarEntries = resultPaths.get().stream().map(jar::getEntry).collect(Collectors.toList()); + classes.put(fqn, mapper.apply(jar, jarEntries)); + foundClassesInThisJar = true; + } + } + return foundClassesInThisJar; + } + + public static void find( + Map> classes, + List searchPaths, + String suffix, + Function, List> fileMapper, + BiFunction, List> entryMapper) { + for (var searchPath : searchPaths) { + File searchFile = new File(searchPath); + if (searchFile.isDirectory()) { + findFilesInPath(searchPath, suffix, classes, fileMapper); + } else if (searchFile.isFile() && searchPath.endsWith(".jar")) { + var jarFile = wrapCheckedException(JarFile::new, searchPath); + var useful = findFilesInJar(classes, jarFile, suffix, entryMapper); + if (!useful) { + wrapCheckedException(jarFile::close); + } + } + } + } + + private static List getJavaFileObjectsFromFiles( + List paths, StandardJavaFileManager fm) { + var result = new ArrayList(); + var files = StreamUtil.map(paths, Path::toFile); + fm.getJavaFileObjectsFromFiles(files).forEach(result::add); + return result; + } + + private static List getJavaFileObjectsFromJar( + JarFile jarFile, List entries) { + return StreamUtil.map(entries, (entry) -> new JarEntryFileObject(jarFile, entry)); + } + + private static List getInputStreamProvidersFromFiles(List files) { + return StreamUtil.map(files, (path) -> new FileInputStreamProvider(path.toFile())); + } + + private static List getInputStreamProvidersFromJar( + JarFile jarFile, List entries) { + return StreamUtil.map(entries, entry -> new JarEntryInputStreamProvider(jarFile, entry)); + } + + public static void findJavaSources( + Map> classes, + List searchPaths, + StandardJavaFileManager fm) { + find( + classes, + searchPaths, + ".java", + files -> getJavaFileObjectsFromFiles(files, fm), + ClassFinder::getJavaFileObjectsFromJar); + } + + public static void findJavaClasses( + Map> classes, List searchPaths) { + find( + classes, + searchPaths, + ".class", + ClassFinder::getInputStreamProvidersFromFiles, + ClassFinder::getInputStreamProvidersFromJar); + } +} 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 000000000..6b4c8bd15 --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/util/ExceptionUtil.java @@ -0,0 +1,33 @@ +package com.github.dart_lang.jnigen.apisummarizer.util; + +public class ExceptionUtil { + @FunctionalInterface + public interface CheckedFunction { + R function(T value) throws Exception; + } + + @FunctionalInterface + public interface CheckedRunnable { + void run() throws Exception; + } + + /** + * Wraps a function throwing a checked exception and throws all checked exceptions as runtime + * exceptions. + */ + public static R wrapCheckedException(CheckedFunction function, T value) { + try { + return function.function(value); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static void wrapCheckedException(CheckedRunnable runnable) { + try { + runnable.run(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/util/FileInputStreamProvider.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/util/FileInputStreamProvider.java new file mode 100644 index 000000000..da5cadf9e --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/util/FileInputStreamProvider.java @@ -0,0 +1,38 @@ +package com.github.dart_lang.jnigen.apisummarizer.util; + +import java.io.*; + +/** Implementation of InputStreamProvider backed by a File. */ +public class FileInputStreamProvider implements InputStreamProvider { + File file; + InputStream stream; + + public FileInputStreamProvider(File file) { + this.file = file; + } + + @Override + public InputStream getInputStream() { + if (stream == null) { + try { + stream = new FileInputStream(file); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } + } + return stream; + } + + @Override + public void close() { + if (stream == null) { + return; + } + try { + stream.close(); + stream = null; + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/util/InputStreamProvider.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/util/InputStreamProvider.java new file mode 100644 index 000000000..85ba15b2e --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/util/InputStreamProvider.java @@ -0,0 +1,17 @@ +package com.github.dart_lang.jnigen.apisummarizer.util; + +import java.io.InputStream; + +/** + * Implementers of this interface provide an InputStream on-demand for writing, and provide a way to + * close the same.
+ * The implementation doesn't need to be thread-safe, since this is only used in AsmSummarizer, + * which reads the classes serially. + */ +public interface InputStreamProvider { + /** Return the input stream, initializing it if needed. */ + InputStream getInputStream(); + + /** close the underlying InputStream. */ + void close(); +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/util/JarEntryFileObject.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/util/JarEntryFileObject.java new file mode 100644 index 000000000..49f187fe8 --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/util/JarEntryFileObject.java @@ -0,0 +1,41 @@ +package com.github.dart_lang.jnigen.apisummarizer.util; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.jar.JarFile; +import java.util.zip.ZipEntry; +import javax.tools.SimpleJavaFileObject; + +/** Implements JavaFileObject for use by Doclet summarizer. */ +class JarEntryFileObject extends SimpleJavaFileObject { + JarFile jarFile; + String relativePath; + + protected JarEntryFileObject(JarFile jarFile, ZipEntry entry) { + super(URI.create(new File(jarFile.getName()).toURI() + "/" + entry.getName()), Kind.SOURCE); + this.jarFile = jarFile; + this.relativePath = entry.getName(); + } + + private int getEntrySize(ZipEntry entry) { + long limit = 1024L * 1024L * 16L; // Arbitrary limit, how long can be a source file? + long size = entry.getSize(); + return (int) Long.min(size, limit); + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + var entry = jarFile.getEntry(relativePath); + var out = new ByteArrayOutputStream(getEntrySize(entry)); + + try (var stream = jarFile.getInputStream(entry)) { + stream.transferTo(out); + } catch (IOException e) { + throw new RuntimeException(e); + } + return out.toString(StandardCharsets.UTF_8); + } +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/util/JarEntryInputStreamProvider.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/util/JarEntryInputStreamProvider.java new file mode 100644 index 000000000..cba3f76bd --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/util/JarEntryInputStreamProvider.java @@ -0,0 +1,29 @@ +package com.github.dart_lang.jnigen.apisummarizer.util; + +import java.io.IOException; +import java.io.InputStream; +import java.util.jar.JarFile; +import java.util.zip.ZipEntry; + +public class JarEntryInputStreamProvider implements InputStreamProvider { + + private final JarFile jarFile; + private final ZipEntry zipEntry; + + public JarEntryInputStreamProvider(JarFile jarFile, ZipEntry zipEntry) { + this.jarFile = jarFile; + this.zipEntry = zipEntry; + } + + @Override + public InputStream getInputStream() { + try { + return jarFile.getInputStream(zipEntry); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public void close() {} +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/util/JsonWriter.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/util/JsonWriter.java new file mode 100644 index 000000000..112e241f7 --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/util/JsonWriter.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 JsonWriter { + public static void writeJSON(List classes, OutputStream output) { + var mapper = new ObjectMapper(); + Log.info("Writing JSON for %d classes", classes.size()); + mapper.enable(SerializationFeature.INDENT_OUTPUT); + mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY); + try { + mapper.writeValue(output, classes); + } catch (IOException e) { + e.printStackTrace(); + } + Log.info("Finished"); + } +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/util/Log.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/util/Log.java new file mode 100644 index 000000000..dfb48e18c --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/util/Log.java @@ -0,0 +1,25 @@ +// 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.util; + +import java.util.logging.Level; +import java.util.logging.Logger; + +public class Log { + private static final Logger logger = Logger.getLogger("ApiSummarizer"); + + private static void log(Level level, String format, Object... args) { + String formatted = String.format(format, args); + logger.log(level, formatted); + } + + public static void info(String format, Object... args) { + log(Level.INFO, format, args); + } + + public static void warning(String format, Object... args) { + log(Level.WARNING, format, args); + } +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/util/SkipException.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/util/SkipException.java new file mode 100644 index 000000000..1f253b08a --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/util/SkipException.java @@ -0,0 +1,13 @@ +// 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.util; + +// Generic skip exception when the code cannot decide how to handle an element. +// The caller in some above layer can catch this and skip to appropriate extent. +public class SkipException extends RuntimeException { + public SkipException(String message) { + super(message); + } +} diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/util/StreamUtil.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/util/StreamUtil.java new file mode 100644 index 000000000..30a8fa0bd --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/util/StreamUtil.java @@ -0,0 +1,26 @@ +// 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.util; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class StreamUtil { + public static List map(List list, Function function) { + return list.stream().map(function).collect(Collectors.toList()); + } + + public static List map(T[] array, Function function) { + return Arrays.stream(array).map(function).collect(Collectors.toList()); + } + + public static List flattenListValues(Map> map) { + return map.values().stream() + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + } +} diff --git a/pkgs/jnigen/java/src/test/java/com/github/dart_lang/jnigen/apisummarizer/ClassFinderTest.java b/pkgs/jnigen/java/src/test/java/com/github/dart_lang/jnigen/apisummarizer/ClassFinderTest.java new file mode 100644 index 000000000..4209e3a2e --- /dev/null +++ b/pkgs/jnigen/java/src/test/java/com/github/dart_lang/jnigen/apisummarizer/ClassFinderTest.java @@ -0,0 +1,95 @@ +package com.github.dart_lang.jnigen.apisummarizer; + +import static com.github.dart_lang.jnigen.apisummarizer.util.ClassFinder.findClassAndChildren; +import static com.github.dart_lang.jnigen.apisummarizer.util.ClassFinder.isNestedClassOf; +import static org.junit.Assert.*; + +import java.util.*; +import java.util.stream.Collectors; +import org.junit.Test; + +public class ClassFinderTest { + @Test + public void testNestedClassCheck() { + assertTrue( + "Single nested class", + isNestedClassOf("com/abc/Class$Nested.class", "com/abc/Class", ".class")); + assertTrue( + "Nested twice", + isNestedClassOf("com/abc/Class$Nested$Twice.class", "com/abc/Class", ".class")); + assertTrue( + "Single nested class - backslash separator", + isNestedClassOf("com\\abc\\Class$Nested.class", "com\\abc\\Class", ".class")); + assertFalse( + "Anon inner class", isNestedClassOf("com/abc/Class$1.class", "com/abc/Class", ".class")); + assertFalse( + "Anon inner class inside nested class", + isNestedClassOf("com/abc/Class$Nested$1.class", "com/abc/Class", ".class")); + assertFalse( + "Different class name", + isNestedClassOf("com/abc/AClass$Nested.class", "com/abc/Class", ".class")); + } + + private Optional> pathListOf(String sep, String... paths) { + List pathList = + Arrays.stream(paths).map(path -> path.replace("/", sep)).collect(Collectors.toList()); + return Optional.of(pathList); + } + + @Test + public void testFindChildren() { + TreeSet entriesWithSlash = + new TreeSet<>( + List.of( + "random/os/App.class", + "random/os/App$1.class", + "random/os/App$1$3.class", + "random/os/Process.class", + "random/os/Process$Fork.class", + "random/os/Process$Fork$1.class", + "random/os/Process$Fork$A$B$C$2.class", + "random/widget/Dialog.class", + "random/widget/Dialog$Button.class", + "random/widget/Dialog$Button$2.class", + "random/widget/Dialog$Button$Color.class", + "random/widget/Dialogue$Button.class", + "random/time/Clock.class", + "random/time/Clock$1.class", + "random/time/Calendar.class", + "random/time/Calendar$Month$1.class", + "random/time/Calendar$Month.class")); + TreeSet entriesWithBackslash = + entriesWithSlash.stream() + .map(x -> x.replace('/', '\\')) + .collect(Collectors.toCollection(TreeSet::new)); + Map> bySeparater = + Map.of("/", entriesWithSlash, "\\", entriesWithBackslash); + + for (var sep : bySeparater.keySet()) { + var entries = bySeparater.get(sep); + assertEquals( + pathListOf(sep, "random/os/Process$Fork.class", "random/os/Process.class"), + findClassAndChildren(entries, "random.os.Process", sep, ".class")); + assertEquals( + pathListOf( + sep, + "random/time/Calendar$Month.class", + "random/time/Calendar.class", + "random/time/Clock.class"), + findClassAndChildren(entries, "random.time", sep, ".class")); + assertEquals( + pathListOf( + sep, + "random/widget/Dialog$Button$Color.class", + "random/widget/Dialog$Button.class", + "random/widget/Dialog.class"), + findClassAndChildren(entries, "random.widget.Dialog", sep, ".class")); + assertEquals( + pathListOf(sep, "random/os/App.class"), + findClassAndChildren(entries, "random.os.App", sep, ".class")); + assertEquals( + pathListOf(sep, "random/os/App.class"), + findClassAndChildren(entries, "random.os.App", sep, ".class")); + } + } +} 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 000000000..b02ee15e5 --- /dev/null +++ b/pkgs/jnigen/java/src/test/java/com/github/dart_lang/jnigen/apisummarizer/JSONComparisonTest.java @@ -0,0 +1,53 @@ +package com.github.dart_lang.jnigen.apisummarizer; + +import com.github.dart_lang.jnigen.apisummarizer.util.Log; +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"); + Log.info("Temporary file: %s", tempFile.getPath()); + Main.main( + new String[] { + "-s", "src/test/resources", "com.example.Example", "-o", tempFile.getPath(), + }); + int comparison = gitDiff(exampleClassJsonOutput, tempFile); + if (comparison != 0) { + Log.warning("New output (%s) is different than reference output.", tempFile.getPath()); + } + + // Fail test if git diff exited with 1 + Assert.assertEquals(0, comparison); + + var deleted = tempFile.delete(); + if (!deleted) { + Log.warning("Cannot delete temp file %s", tempFile.getPath()); + } + } +} diff --git a/pkgs/jnigen/java/src/test/resources/com/example/Example.java b/pkgs/jnigen/java/src/test/resources/com/example/Example.java new file mode 100644 index 000000000..b5856a277 --- /dev/null +++ b/pkgs/jnigen/java/src/test/resources/com/example/Example.java @@ -0,0 +1,39 @@ +// 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.example; + +public class Example { + public static final boolean staticFinalField = true; + + public Example(int instanceField) { + this.instanceField = instanceField; + } + + public static String staticField = "hello"; + + public static String getStaticField() { + return staticField; + } + + public int instanceField; + + public int getInstanceField() { + return instanceField; + } + + protected int overrideableMethod(int x, int y) {} + + int defaultAccessNotVisible(); + + private int privateAccessNotVisible(); + + public static class Aux extends Example { + public static int nothing = 0; + + public static Example getAnExample() { + return new Example(); + } + } +} 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 000000000..6786a269b --- /dev/null +++ b/pkgs/jnigen/java/src/test/resources/exampleClassSummary.json @@ -0,0 +1,185 @@ +[ { + "declKind" : "CLASS", + "modifiers" : [ "public" ], + "binaryName" : "com.example.Example", + "methods" : [ { + "modifiers" : [ "public" ], + "name" : "", + "params" : [ { + "name" : "instanceField", + "type" : { + "shorthand" : "int", + "kind" : "PRIMITIVE", + "type" : { + "name" : "int" + } + } + } ], + "returnType" : { + "shorthand" : "void", + "kind" : "PRIMITIVE", + "type" : { + "name" : "void" + } + } + }, { + "modifiers" : [ "static", "public" ], + "name" : "getStaticField", + "returnType" : { + "shorthand" : "java.lang.String", + "kind" : "DECLARED", + "type" : { + "binaryName" : "java.lang.String", + "simpleName" : "String" + } + } + }, { + "modifiers" : [ "public" ], + "name" : "getInstanceField", + "returnType" : { + "shorthand" : "int", + "kind" : "PRIMITIVE", + "type" : { + "name" : "int" + } + } + }, { + "modifiers" : [ "protected" ], + "name" : "overrideableMethod", + "params" : [ { + "name" : "x", + "type" : { + "shorthand" : "int", + "kind" : "PRIMITIVE", + "type" : { + "name" : "int" + } + } + }, { + "name" : "y", + "type" : { + "shorthand" : "int", + "kind" : "PRIMITIVE", + "type" : { + "name" : "int" + } + } + } ], + "returnType" : { + "shorthand" : "int", + "kind" : "PRIMITIVE", + "type" : { + "name" : "int" + } + } + }, { + "name" : "defaultAccessNotVisible", + "returnType" : { + "shorthand" : "int", + "kind" : "PRIMITIVE", + "type" : { + "name" : "int" + } + } + }, { + "modifiers" : [ "private" ], + "name" : "privateAccessNotVisible", + "returnType" : { + "shorthand" : "int", + "kind" : "PRIMITIVE", + "type" : { + "name" : "int" + } + } + } ], + "fields" : [ { + "modifiers" : [ "static", "public", "final" ], + "name" : "staticFinalField", + "type" : { + "shorthand" : "boolean", + "kind" : "PRIMITIVE", + "type" : { + "name" : "boolean" + } + }, + "defaultValue" : true + }, { + "modifiers" : [ "static", "public" ], + "name" : "staticField", + "type" : { + "shorthand" : "java.lang.String", + "kind" : "DECLARED", + "type" : { + "binaryName" : "java.lang.String", + "simpleName" : "String" + } + } + }, { + "modifiers" : [ "public" ], + "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" ], + "binaryName" : "com.example.Example$Aux", + "methods" : [ { + "modifiers" : [ "public" ], + "name" : "", + "returnType" : { + "shorthand" : "void", + "kind" : "PRIMITIVE", + "type" : { + "name" : "void" + } + } + }, { + "modifiers" : [ "static", "public" ], + "name" : "getAnExample", + "returnType" : { + "shorthand" : "com.example.Example", + "kind" : "DECLARED", + "type" : { + "binaryName" : "com.example.Example", + "simpleName" : "Example" + } + } + } ], + "fields" : [ { + "modifiers" : [ "static", "public" ], + "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/lib/jnigen.dart b/pkgs/jnigen/lib/jnigen.dart new file mode 100644 index 000000000..8e2ebe043 --- /dev/null +++ b/pkgs/jnigen/lib/jnigen.dart @@ -0,0 +1,13 @@ +// 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. + +/// This library exports a high level programmatic API to jnigen, the entry +/// point of which is runJniGenTask function, which takes run configuration as +/// a JniGenTask. +library jnigen; + +export 'src/elements/elements.dart'; +export 'src/config/config.dart'; +export 'src/config/filters.dart'; +export 'src/generate_bindings.dart'; diff --git a/pkgs/jnigen/lib/src/bindings/c_generator.dart b/pkgs/jnigen/lib/src/bindings/c_generator.dart new file mode 100644 index 000000000..79b07c8b6 --- /dev/null +++ b/pkgs/jnigen/lib/src/bindings/c_generator.dart @@ -0,0 +1,383 @@ +// Copyright (c) 2023, 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. + +import 'dart:io'; + +import '../config/config.dart'; +import '../elements/elements.dart'; +import '../logging/logging.dart'; +import '../util/find_package.dart'; +import '../util/string_util.dart'; +import 'visitor.dart'; + +class CFieldName extends Visitor { + const CFieldName(); + + @override + String visit(Field node) { + final className = node.classDecl.uniqueName; + final fieldName = node.finalName; + return '${className}__$fieldName'; + } +} + +class CMethodName extends Visitor { + const CMethodName(); + + @override + String visit(Method node) { + final className = node.classDecl.uniqueName; + final methodName = node.finalName; + return '${className}__$methodName'; + } +} + +class CGenerator extends Visitor> { + static const _prelude = '''// Autogenerated by jnigen. DO NOT EDIT! + +#include +#include "jni.h" +#include "dartjni.h" + +thread_local JNIEnv *jniEnv; +JniContext *jni; + +JniContext *(*context_getter)(void); +JNIEnv *(*env_getter)(void); + +void setJniGetters(JniContext *(*cg)(void), + JNIEnv *(*eg)(void)) { + context_getter = cg; + env_getter = eg; +} + +'''; + + final Config config; + + CGenerator(this.config); + + Future _copyFileFromPackage(String package, String relPath, Uri target, + {String Function(String)? transform}) async { + final packagePath = await findPackageRoot(package); + if (packagePath != null) { + final sourceFile = File.fromUri(packagePath.resolve(relPath)); + final targetFile = await File.fromUri(target).create(recursive: true); + var source = await sourceFile.readAsString(); + if (transform != null) { + source = transform(source); + } + await targetFile.writeAsString(source); + } else { + log.warning('package $package not found! ' + 'skipped copying ${target.toFilePath()}'); + } + } + + @override + Future visit(Classes node) async { + // Write C file and init file. + final cConfig = config.outputConfig.cConfig!; + final cRoot = cConfig.path; + final preamble = config.preamble; + log.info("Using c root = $cRoot"); + final libraryName = cConfig.libraryName; + log.info('Creating dart init file ...'); + // Create C file. + final subdir = cConfig.subdir ?? '.'; + final cFileRelativePath = '$subdir/$libraryName.c'; + final cFile = await File.fromUri(cRoot.resolve(cFileRelativePath)) + .create(recursive: true); + final cFileStream = cFile.openWrite(); + // Write C Bindings. + if (preamble != null) { + cFileStream.writeln(preamble); + } + cFileStream.write(_prelude); + final classGenerator = _CClassGenerator(config, cFileStream); + for (final classDecl in node.decls.values) { + classDecl.accept(classGenerator); + } + await cFileStream.close(); + log.info('Copying auxiliary files...'); + for (final file in ['dartjni.h', '.clang-format']) { + await _copyFileFromPackage( + 'jni', 'src/$file', cRoot.resolve('$subdir/$file')); + } + await _copyFileFromPackage( + 'jnigen', 'cmake/CMakeLists.txt.tmpl', cRoot.resolve('CMakeLists.txt'), + transform: (s) { + return s + .replaceAll('{{LIBRARY_NAME}}', libraryName) + .replaceAll('{{SUBDIR}}', subdir); + }); + log.info('Running clang-format on C bindings'); + try { + final clangFormat = Process.runSync('clang-format', ['-i', cFile.path]); + if (clangFormat.exitCode != 0) { + printError(clangFormat.stderr); + log.warning('clang-format exited with ${clangFormat.exitCode}'); + } + } on ProcessException catch (e) { + log.warning('cannot run clang-format: $e'); + } + } +} + +const _classVarPrefix = '_c_'; +const _jniResultType = 'JniResult'; +const _loadEnvCall = 'load_env();'; +const _ifError = + '(JniResult){.value = {.j = 0}, .exception = check_exception()}'; + +class _CClassGenerator extends Visitor { + final Config config; + final StringSink s; + + _CClassGenerator(this.config, this.s); + + @override + void visit(ClassDecl node) { + final classNameInC = node.uniqueName; + final classVar = '$_classVarPrefix$classNameInC'; + // Global variable in C that holds the reference to class. + s.write('''// ${node.binaryName} +jclass $classVar = NULL; + +'''); + + final methodGenerator = _CMethodGenerator(config, s); + for (final method in node.methods) { + method.accept(methodGenerator); + } + + final fieldGenerator = _CFieldGenerator(config, s); + for (final field in node.fields) { + field.accept(fieldGenerator); + } + } +} + +class _CLoadClassGenerator extends Visitor { + _CLoadClassGenerator(); + + @override + String visit(ClassDecl node) { + final classVar = '$_classVarPrefix${node.uniqueName}'; + return ''' load_class_global_ref(&$classVar, "${node.internalName}"); + if ($classVar == NULL) return $_ifError;'''; + } +} + +class _CMethodGenerator extends Visitor { + static const _methodVarPrefix = '_m_'; + + final Config config; + final StringSink s; + + _CMethodGenerator(this.config, this.s); + + @override + void visit(Method node) { + final classNameInC = node.classDecl.uniqueName; + + final cMethodName = node.accept(const CMethodName()); + final classRef = '$_classVarPrefix$classNameInC'; + final methodId = '$_methodVarPrefix$cMethodName'; + final cMethodParams = [ + if (!node.isCtor && !node.isStatic) 'jobject self_', + ...node.params.accept(const _CParamGenerator(addReturnType: true)), + ].join(','); + final jniSignature = node.descriptor; + final ifStaticMethodID = node.isStatic ? 'static_' : ''; + + var javaReturnType = node.returnType.type; + if (node.isCtor) { + javaReturnType = DeclaredType( + binaryName: node.classDecl.binaryName, + ); + } + final callType = node.returnType.accept(const _CTypeCallSite()); + final callArgs = [ + 'jniEnv', + if (!node.isCtor && !node.isStatic) 'self_' else classRef, + methodId, + ...node.params.accept(const _CParamGenerator(addReturnType: false)) + ].join(', '); + + var ifAssignResult = ''; + if (javaReturnType.name != 'void') { + ifAssignResult = + '${javaReturnType.accept(const _CReturnType())} _result = '; + } + + final ifStaticCall = node.isStatic ? 'Static' : ''; + final envMethod = + node.isCtor ? 'NewObject' : 'Call$ifStaticCall${callType}Method'; + final returnResultIfAny = javaReturnType.accept(const _CResult()); + s.write(''' +jmethodID $methodId = NULL; +FFI_PLUGIN_EXPORT +$_jniResultType $cMethodName($cMethodParams) { + $_loadEnvCall + ${node.classDecl.accept(_CLoadClassGenerator())} + load_${ifStaticMethodID}method($classRef, + &$methodId, "${node.name}", "$jniSignature"); + if ($methodId == NULL) return $_ifError; + $ifAssignResult(*jniEnv)->$envMethod($callArgs); + $returnResultIfAny +} + +'''); + } +} + +class _CFieldGenerator extends Visitor { + static const _fieldVarPrefix = '_f_'; + + final Config config; + final StringSink s; + + _CFieldGenerator(this.config, this.s); + + @override + void visit(Field node) { + final cClassName = node.classDecl.uniqueName; + + final fieldName = node.finalName; + final fieldNameInC = node.accept(const CFieldName()); + final fieldVar = "$_fieldVarPrefix$fieldNameInC"; + + // If the field is final and default is assigned, then no need to wrap + // this field. It should then be a constant in dart code. + if (node.isStatic && node.isFinal && node.defaultValue != null) { + return; + } + + s.write('jfieldID $fieldVar = NULL;\n'); + + final classVar = '$_classVarPrefix$cClassName'; + void writeAccessor({bool isSetter = false}) { + const cReturnType = _jniResultType; + final cMethodPrefix = isSetter ? 'set' : 'get'; + final formalArgs = [ + if (!node.isStatic) 'jobject self_', + if (isSetter) '${node.type.accept(const _CReturnType())} value', + ].join(', '); + final ifStaticField = node.isStatic ? 'static_' : ''; + final ifStaticCall = node.isStatic ? 'Static' : ''; + final callType = node.type.accept(const _CTypeCallSite()); + final objectArgument = node.isStatic ? classVar : 'self_'; + + String accessorStatements; + if (isSetter) { + accessorStatements = + ' (*jniEnv)->Set$ifStaticCall${callType}Field(jniEnv, ' + '$objectArgument, $fieldVar, value);\n' + ' return $_ifError;'; + } else { + final getterExpr = + '(*jniEnv)->Get$ifStaticCall${callType}Field(jniEnv, ' + '$objectArgument, $fieldVar)'; + final cResultType = node.type.accept(const _CReturnType()); + final result = node.type.accept(const _CResult()); + accessorStatements = ''' $cResultType _result = $getterExpr; + $result'''; + } + s.write(''' +FFI_PLUGIN_EXPORT +$cReturnType ${cMethodPrefix}_$fieldNameInC($formalArgs) { + $_loadEnvCall + ${node.classDecl.accept(_CLoadClassGenerator())} + load_${ifStaticField}field($classVar, &$fieldVar, "$fieldName", + "${node.type.descriptor}"); +$accessorStatements +} + +'''); + } + + writeAccessor(isSetter: false); + if (node.isFinal) { + return; + } + writeAccessor(isSetter: true); + } +} + +class _CParamGenerator extends Visitor { + /// These should be avoided in parameter names. + static const _cTypeKeywords = { + 'short', + 'char', + 'int', + 'long', + 'float', + 'double', + }; + + const _CParamGenerator({required this.addReturnType}); + + final bool addReturnType; + + @override + String visit(Param node) { + final paramName = + (_cTypeKeywords.contains(node.name) ? '${node.name}0' : node.name) + .replaceAll('\$', '_'); + if (addReturnType) { + final type = node.type.accept(const _CReturnType()); + return '$type $paramName'; + } + return paramName; + } +} + +class _CReturnType extends TypeVisitor { + const _CReturnType(); + + @override + String visitNonPrimitiveType(ReferredType node) { + return 'jobject'; + } + + @override + String visitPrimitiveType(PrimitiveType node) { + return node.cType; + } +} + +class _CTypeCallSite extends TypeVisitor { + const _CTypeCallSite(); + + @override + String visitNonPrimitiveType(ReferredType node) { + return 'Object'; + } + + @override + String visitPrimitiveType(PrimitiveType node) { + return node.name.capitalize(); + } +} + +class _CResult extends TypeVisitor { + const _CResult(); + + @override + String visitNonPrimitiveType(ReferredType node) { + return 'return to_global_ref_result(_result);'; + } + + @override + String visitPrimitiveType(PrimitiveType node) { + if (node.name == 'void') { + return 'return $_ifError;'; + } + // The union field is the same as the type's signature, but in lowercase. + final unionField = node.signature.toLowerCase(); + return 'return (JniResult){.value = {.$unionField = _result}, ' + '.exception = check_exception()};'; + } +} diff --git a/pkgs/jnigen/lib/src/bindings/dart_generator.dart b/pkgs/jnigen/lib/src/bindings/dart_generator.dart new file mode 100644 index 000000000..9c2069299 --- /dev/null +++ b/pkgs/jnigen/lib/src/bindings/dart_generator.dart @@ -0,0 +1,1731 @@ +// Copyright (c) 2023, 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. + +import 'dart:io'; + +import 'package:meta/meta.dart'; + +import '../config/config.dart'; +import '../config/experiments.dart'; +import '../elements/elements.dart'; +import '../logging/logging.dart'; +import '../util/string_util.dart'; +import 'c_generator.dart'; +import 'resolver.dart'; +import 'visitor.dart'; + +// Import prefixes. +const _jni = 'jni'; +const _ffi = 'ffi'; + +// package:jni types. +const _jType = '$_jni.JObjType'; +const _jPointer = '$_jni.JObjectPtr'; +const _jArray = '$_jni.JArray'; +const _jObject = '$_jni.JObject'; +const _jResult = '$_jni.JniResult'; +const _jCallType = '$_jni.JniCallType'; + +// package:ffi types. +const _voidPointer = '$_ffi.Pointer<$_ffi.Void>'; + +// Prefixes and suffixes. +const _typeParamPrefix = '\$'; + +// Misc. +const _protectedExtension = 'ProtectedJniExtensions'; +const _classRef = '_class.reference'; +const _env = '$_jni.Jni.env'; +const _accessors = '$_jni.Jni.accessors'; +const _lookup = 'jniLookup'; +const _selfPointer = 'reference'; + +// Docs. +const _releaseInstruction = + ' /// The returned object must be released after use, ' + 'by calling the [release] method.'; + +extension on Iterable { + /// Similar to [join] but adds the [separator] to the end as well. + String delimited([String separator = '']) { + return map((e) => '$e$separator').join(); + } +} + +/// Encloses [inside] in the middle of [open] and [close] +/// if [inside] is not empty. +String _encloseIfNotEmpty(String open, String inside, String close) { + if (inside == '') return ''; + return '$open$inside$close'; +} + +String _newLine({int depth = 0}) { + return '\n${' ' * depth}'; +} + +/// Merges two maps. For the same keys, their value lists will be concatenated. +/// +/// ** After calling this, the original maps might get modified! ** +Map> _mergeMapValues(Map> a, Map> b) { + final merged = >{}; + for (final key in {...a.keys, ...b.keys}) { + if (!a.containsKey(key)) { + merged[key] = b[key]!; + continue; + } + if (!b.containsKey(key)) { + merged[key] = a[key]!; + continue; + } + + // Merging the smaller one to the bigger one + if (a[key]!.length > b[key]!.length) { + merged[key] = a[key]!; + merged[key]!.addAll(b[key]!); + } else { + merged[key] = b[key]!; + merged[key]!.addAll(a[key]!); + } + } + return merged; +} + +/// **Naming Convention** +/// +/// Let's take the following code as an example: +/// +/// ```dart +/// Method definition +/// void f(JType $T, JType $U, T t, U u) { +/// // ... +/// } +/// f($T, $U, t, u); // Calling the Method +/// ``` +/// +/// Here `f` will be replaced according to the place of usage. +/// +/// * `fArgsDef` refers to `T t, U u` – the arguments in the method +/// definition. +/// * `fArgsCall` refer to `t, u` – the arguments passed to call the method. +/// * `fTypeParamsDef` refers to `` – the type parameters +/// of the method at the point of definition. +/// * `fTypeParamsCall` refers to `` – the type parameters when +/// calling, or whenever we don't want to have the `extends` keyword. +/// * `fTypeClassesDef` refers to `JType $T, JType $U`. +/// * `fTypeClassesCall` refers to `$T, $U` when calling the method. +class DartGenerator extends Visitor> { + final Config config; + + DartGenerator(this.config); + + static const cInitImport = 'import "dart:ffi" as ffi;\n' + 'import "package:jni/internal_helpers_for_jnigen.dart";\n'; + + /// Initialization code for C based bindings. + /// + /// Should be called once in a package. In package-structured bindings + /// this is placed in _init.dart in package root. + String get cInitCode => ''' +// Auto-generated initialization code. + +final $_ffi.Pointer Function(String sym) $_lookup = + $_protectedExtension.initGeneratedLibrary("${config.outputConfig.cConfig!.libraryName}"); + + +'''; + + static const autoGeneratedNotice = '// Autogenerated by jnigen. ' + 'DO NOT EDIT!\n\n'; + static const defaultImports = ''' +import "dart:isolate" show ReceivePort; +import "dart:ffi" as ffi; +import "package:jni/internal_helpers_for_jnigen.dart"; +import "package:jni/jni.dart" as jni; + +'''; + + // Sort alphabetically. + static const defaultLintSuppressions = ''' +// ignore_for_file: annotate_overrides +// ignore_for_file: camel_case_extensions +// ignore_for_file: camel_case_types +// ignore_for_file: constant_identifier_names +// ignore_for_file: file_names +// ignore_for_file: lines_longer_than_80_chars +// ignore_for_file: no_leading_underscores_for_local_identifiers +// ignore_for_file: non_constant_identifier_names +// ignore_for_file: overridden_fields +// ignore_for_file: unnecessary_cast +// ignore_for_file: unused_element +// ignore_for_file: unused_field +// ignore_for_file: unused_import +// ignore_for_file: unused_local_variable +// ignore_for_file: unused_shown_name + +'''; + static const preImportBoilerplate = + autoGeneratedNotice + defaultLintSuppressions + defaultImports; + + /// Run dart format command on [path]. + Future _runDartFormat(String path) async { + log.info('Running dart format...'); + final formatRes = await Process.run('dart', ['format', path]); + // if negative exit code, likely due to an interrupt. + if (formatRes.exitCode > 0) { + log.fatal('Dart format completed with exit code ${formatRes.exitCode} ' + 'This usually means there\'s a syntax error in bindings.\n' + 'Please look at the generated files and report a bug: \n' + 'https://github.com/dart-lang/jnigen/issues/new\n'); + } + } + + @override + Future visit(Classes node) async { + final cBased = config.outputConfig.bindingsType == BindingsType.cBased; + final root = config.outputConfig.dartConfig.path; + final preamble = config.preamble ?? ''; + if (config.outputConfig.dartConfig.structure == + OutputStructure.singleFile) { + final file = File.fromUri(root); + await file.create(recursive: true); + log.info("Generating ${cBased ? "C + Dart" : "Pure Dart"} Bindings"); + final s = file.openWrite(); + s.writeln(preamble); + s.writeln(autoGeneratedNotice); + s.writeln(defaultLintSuppressions); + s.writeln(defaultImports); + if (cBased) { + s.writeln(cInitCode); + } + final resolver = Resolver( + importedClasses: config.importedClasses, + currentClass: null, // Single file mode. + inputClassNames: node.decls.keys.toSet(), + ); + final classGenerator = _ClassGenerator(config, s, resolver); + for (final classDecl in node.decls.values) { + classDecl.accept(classGenerator); + } + await s.close(); + await _runDartFormat(file.path); + return; + } + final files = >{}; + final packages = >{}; + for (final classDecl in node.decls.values) { + final fileClass = Resolver.getFileClassName(classDecl.binaryName); + + files.putIfAbsent(fileClass, () => []); + files[fileClass]!.add(classDecl); + + packages.putIfAbsent(classDecl.packageName, () => {}); + packages[classDecl.packageName]!.add(fileClass.split('.').last); + } + + log.info("Using dart root = $root"); + const initFileName = '_init.dart'; + if (cBased) { + final initFileUri = root.resolve(initFileName); + final initFile = File.fromUri(initFileUri); + await initFile.create(recursive: true); + final initStream = initFile.openWrite(); + initStream.writeln(preamble); + initStream.writeln(cInitImport); + initStream.writeln(cInitCode); + await initStream.close(); + } + for (var fileClassName in files.keys) { + final relativeFileName = '${fileClassName.replaceAll('.', '/')}.dart'; + final dartFileUri = root.resolve(relativeFileName); + final dartFile = await File.fromUri(dartFileUri).create(recursive: true); + log.fine('$fileClassName -> ${dartFile.path}'); + + final classesInFile = files[fileClassName]!; + final dartFileStream = dartFile.openWrite(); + dartFileStream.writeln(preamble); + dartFileStream.writeln(autoGeneratedNotice); + dartFileStream.writeln(defaultLintSuppressions); + dartFileStream.writeln(defaultImports); + final s = StringBuffer(); + if (cBased) { + final initFilePath = ('../' * + relativeFileName.codeUnits + .where((cu) => cu == '/'.codeUnitAt(0)) + .length) + + initFileName; + s.write('import "$initFilePath";'); + } + final resolver = Resolver( + importedClasses: config.importedClasses, + currentClass: fileClassName, + inputClassNames: node.decls.keys.toSet(), + ); + final classGenerator = _ClassGenerator(config, s, resolver); + for (final classDecl in classesInFile) { + classDecl.accept(classGenerator); + } + dartFileStream.writeAll(resolver.getImportStrings(), '\n'); + dartFileStream.writeln(s.toString()); + await dartFileStream.close(); + } + + // write _package.dart export files + for (var package in packages.keys) { + final dirUri = root.resolve('${package.replaceAll('.', '/')}/'); + final exportFileUri = dirUri.resolve("_package.dart"); + final exportFile = File.fromUri(exportFileUri); + exportFile.createSync(recursive: true); + final exports = + packages[package]!.map((cls) => 'export "$cls.dart";').join('\n'); + exportFile.writeAsStringSync(exports); + } + await _runDartFormat(root.toFilePath()); + log.info('Completed.'); + } +} + +/// Generates the Dart class definition, type class, and the array extension. +class _ClassGenerator extends Visitor { + final Config config; + final StringSink s; + final Resolver resolver; + + _ClassGenerator( + this.config, + this.s, + this.resolver, + ); + + static const staticTypeGetter = 'type'; + static const instanceTypeGetter = '\$$staticTypeGetter'; + + @override + void visit(ClassDecl node) { + final isDartOnly = + config.outputConfig.bindingsType == BindingsType.dartOnly; + + // Docs. + s.write('/// from: ${node.binaryName}\n'); + node.javadoc?.accept(_DocGenerator(s, depth: 0)); + + // Class definition. + final name = node.finalName; + final superName = node.superclass!.accept(_TypeGenerator(resolver)); + final implClassName = '\$${name}Impl'; + final typeParamsDef = _encloseIfNotEmpty( + '<', + node.allTypeParams + .accept(const _TypeParamGenerator(withExtends: true)) + .join(', '), + '>', + ); + final typeParams = node.allTypeParams + .accept(const _TypeParamGenerator(withExtends: false)); + final typeParamsCall = _encloseIfNotEmpty( + '<', + typeParams.map((typeParam) => '$_typeParamPrefix$typeParam').join(', '), + '>', + ); + final staticTypeGetterCallArgs = _encloseIfNotEmpty( + '(', + typeParams.join(', '), + ')', + ); + final typeClassesDef = typeParams + .map((typeParam) => + 'final $_jType<$_typeParamPrefix$typeParam> $typeParam;') + .join(_newLine(depth: 1)); + final ctorTypeClassesDef = typeParams + .map((typeParam) => 'this.$typeParam,') + .join(_newLine(depth: 2)); + final superClass = (node.classDecl.superclass!.type as DeclaredType); + final superTypeClassesCall = superClass.classDecl.isObject + ? '' + : superClass.params + .accept(_TypeClassGenerator(resolver)) + .map((typeClass) => '${typeClass.name},') + .join(_newLine(depth: 2)); + s.write(''' +class $name$typeParamsDef extends $superName { + @override + late final $_jType<$name$typeParamsCall> $instanceTypeGetter = $staticTypeGetter$staticTypeGetterCallArgs; + + $typeClassesDef + + $name.fromRef( + $ctorTypeClassesDef + $_jPointer ref, + ): super.fromRef( + $superTypeClassesCall + ref + ); + +'''); + + if (isDartOnly) { + final internalName = node.internalName; + s.write(''' + static final _class = $_jni.Jni.findJClass(r"$internalName"); + +'''); + } + + // Static TypeClass getter. + s.writeln( + ' /// The type which includes information such as the signature of this class.'); + final typeClassName = node.typeClassName; + if (typeParams.isEmpty) { + s.writeln('static const $staticTypeGetter = $typeClassName();'); + } else { + final staticTypeGetterTypeClassesDef = typeParams + .map( + (typeParam) => '$_jType<$_typeParamPrefix$typeParam> $typeParam,') + .join(_newLine(depth: 2)); + final typeClassesCall = + typeParams.map((typeParam) => '$typeParam,').join(_newLine(depth: 3)); + s.write(''' + static $typeClassName$typeParamsCall $staticTypeGetter$typeParamsDef( + $staticTypeGetterTypeClassesDef + ) { + return $typeClassName( + $typeClassesCall + ); + } + +'''); + } + + // Fields and Methods + final fieldGenerator = _FieldGenerator(config, resolver, s); + for (final field in node.fields) { + field.accept(fieldGenerator); + } + final methodGenerator = _MethodGenerator(config, resolver, s); + for (final method in node.methods) { + method.accept(methodGenerator); + } + + // Experimental: Interface implementation. + if (node.declKind == DeclKind.interfaceKind && + (config.experiments?.contains(Experiment.interfaceImplementation) ?? + false)) { + s.write(''' + /// Maps a specific port to the implemented interface. + static final Map _\$impls = {}; +'''); + s.write(r''' + ReceivePort? _$p; + + static jni.JObjectPtr _$invoke( + int port, + jni.JObjectPtr descriptor, + jni.JObjectPtr args, + ) { + return _$invokeMethod( + port, + $MethodInvocation.fromAddresses( + 0, + descriptor.address, + args.address, + ), + ); + } + + static final ffi.Pointer< + ffi.NativeFunction< + jni.JObjectPtr Function( + ffi.Uint64, jni.JObjectPtr, jni.JObjectPtr)>> + _$invokePointer = ffi.Pointer.fromFunction(_$invoke); + + static ffi.Pointer _$invokeMethod( + int $p, + $MethodInvocation $i, + ) { + try { + final $d = $i.methodDescriptor.toDartString(releaseOriginal: true); + final $a = $i.args; + '''); + final proxyMethodIf = _InterfaceMethodIf(resolver, s); + for (final method in node.methods) { + method.accept(proxyMethodIf); + } + s.write(''' + } catch (e) { + return $_protectedExtension.newDartException(e.toString()); + } + return jni.nullptr; + } + + factory $name.implement( + $implClassName$typeParamsCall \$impl, + ) { +'''); + final typeClassesCall = typeParams + .map((typeParam) => '\$impl.$typeParam,') + .join(_newLine(depth: 3)); + s.write(''' + final \$p = ReceivePort(); + final \$x = $name.fromRef( + $typeClassesCall + $_protectedExtension.newPortProxy( + r"${node.binaryName}", + \$p, + _\$invokePointer, + ), + ).._\$p = \$p; + final \$a = \$p.sendPort.nativePort; + _\$impls[\$a] = \$impl; + \$p.listen((\$m) { + if (\$m == null) { + _\$impls.remove(\$p.sendPort.nativePort); + \$p.close(); + return; + } + final \$i = \$MethodInvocation.fromMessage(\$m as List); + final \$r = _\$invokeMethod(\$p.sendPort.nativePort, \$i); + $_protectedExtension.returnResult(\$i.result, \$r); + }); + return \$x; + } + '''); + } + + // Writing any custom code provided for this class. + if (config.customClassBody?.containsKey(node.binaryName) ?? false) { + s.writeln(config.customClassBody![node.binaryName]); + } + + // End of Class definition. + s.writeln('}'); + + // Experimental: Interface implementation + // Abstract and concrete Impl class definition. + // Used for interface implementation. + if (node.declKind == DeclKind.interfaceKind && + (config.experiments?.contains(Experiment.interfaceImplementation) ?? + false)) { + // Abstract Impl class. + final typeClassGetters = typeParams + .map((typeParam) => + '$_jType<$_typeParamPrefix$typeParam> get $typeParam;') + .join(_newLine(depth: 1)); + final abstractFactoryArgs = _encloseIfNotEmpty( + '{', + [ + ...typeParams + .map((typeParam) => 'required $_jType<\$$typeParam> $typeParam,'), + ...node.methods.accept(_ConcreteImplClosureCtorArg(resolver)), + ].join(_newLine(depth: 2)), + '}', + ); + s.write(''' +abstract interface class $implClassName$typeParamsDef { + factory $implClassName( + $abstractFactoryArgs + ) = _$implClassName; + + $typeClassGetters + +'''); + final abstractImplMethod = _AbstractImplMethod(resolver, s); + for (final method in node.methods) { + method.accept(abstractImplMethod); + } + s.writeln('}'); + + // Concrete Impl class. + // This is for passing closures instead of implementing the class. + final concreteCtorArgs = _encloseIfNotEmpty( + '{', + [ + ...typeParams.map((typeParam) => 'required this.$typeParam,'), + ...node.methods.accept(_ConcreteImplClosureCtorArg(resolver)), + ].join(_newLine(depth: 2)), + '}', + ); + final setClosures = _encloseIfNotEmpty( + ' : ', + node.methods + .map((method) => '_${method.finalName} = ${method.finalName}') + .join(', '), + '', + ); + final typeClassesDef = typeParams.map((typeParam) => ''' +@override +final $_jType<\$$typeParam> $typeParam; +''').join(_newLine(depth: 1)); + s.write(''' + +class _$implClassName$typeParamsDef implements $implClassName$typeParamsCall { + _$implClassName( + $concreteCtorArgs + )$setClosures; + + $typeClassesDef + +'''); + final concreteClosureDef = _ConcreteImplClosureDef(resolver, s); + for (final method in node.methods) { + method.accept(concreteClosureDef); + } + s.writeln(); + final concreteMethodDef = _ConcreteImplMethod(resolver, s); + for (final method in node.methods) { + method.accept(concreteMethodDef); + } + s.writeln('}'); + } + // TypeClass definition. + final typeClassesCall = + typeParams.map((typeParam) => '$typeParam,').join(_newLine(depth: 2)); + final signature = node.signature; + final superTypeClass = superClass.accept(_TypeClassGenerator(resolver)); + final hashCodeTypeClasses = typeParams.join(', '); + final equalityTypeClasses = typeParams + .map((typeParam) => ' &&\n $typeParam == other.$typeParam') + .join(); + final hashCode = typeParams.isEmpty + ? '($typeClassName).hashCode' + : 'Object.hash($typeClassName, $hashCodeTypeClasses)'; + s.write(''' +final class $typeClassName$typeParamsDef extends $_jType<$name$typeParamsCall> { + $typeClassesDef + + const $typeClassName( + $ctorTypeClassesDef + ); + + @override + String get signature => r"$signature"; + + @override + $name$typeParamsCall fromRef($_jPointer ref) => $name.fromRef( + $typeClassesCall + ref + ); + + @override + $_jType get superType => ${superTypeClass.name}; + + @override + final superCount = ${node.superCount}; + + @override + int get hashCode => $hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($typeClassName$typeParamsCall) && + other is $typeClassName$typeParamsCall$equalityTypeClasses; + } +} + +'''); + log.finest('Generated bindings for class ${node.binaryName}'); + } +} + +/// Generates the JavaDoc comments. +class _DocGenerator extends Visitor { + final StringSink s; + final int depth; + + const _DocGenerator(this.s, {required this.depth}); + + @override + void visit(JavaDocComment node) { + final link = RegExp('{@link ([^{}]+)}'); + final indent = ' ' * depth; + final comments = node.comment + .replaceAllMapped(link, (match) => match.group(1) ?? '') + .replaceAll('#', '\\#') + .replaceAll('

', '') + .replaceAll('

', '\n') + .replaceAll('', '__') + .replaceAll('', '__') + .replaceAll('', '_') + .replaceAll('', '_') + .split('\n') + .join('\n$indent///'); + s.write(''' +$indent/// +$indent/// $comments +'''); + } +} + +/// Generates the user-facing Dart type. +class _TypeGenerator extends TypeVisitor { + final Resolver? resolver; + + const _TypeGenerator(this.resolver); + + @override + String visitArrayType(ArrayType node) { + final innerType = node.type; + if (innerType.kind == Kind.primitive) { + return '$_jArray<$_jni.j${(innerType.type as PrimitiveType).name}>'; + } + return '$_jArray<${innerType.accept(this)}>'; + } + + @override + String visitDeclaredType(DeclaredType node) { + if (node.classDecl.binaryName == 'java.lang.Object' || + node.classDecl.binaryName == 'java.lang.String') { + return '$_jni.${node.classDecl.finalName}'; + } + + // All type parameters of this type + final allTypeParams = node.classDecl.allTypeParams + .accept(const _TypeParamGenerator(withExtends: false)) + .toList(); + // The ones that are declared. + final definedTypeParams = node.params.accept(this).toList(); + + // Replacing the declared ones. They come at the end. + // The rest will be JObject. + if (allTypeParams.length >= node.params.length) { + allTypeParams.replaceRange( + 0, + allTypeParams.length - node.params.length, + List.filled( + allTypeParams.length - node.params.length, + _jObject, + ), + ); + allTypeParams.replaceRange( + allTypeParams.length - node.params.length, + allTypeParams.length, + definedTypeParams, + ); + } + + final typeParams = _encloseIfNotEmpty('<', allTypeParams.join(', '), '>'); + final prefix = resolver?.resolvePrefix(node.classDecl) ?? ''; + return '$prefix${node.classDecl.finalName}$typeParams'; + } + + @override + String visitPrimitiveType(PrimitiveType node) { + return node.dartType; + } + + @override + String visitTypeVar(TypeVar node) { + return '$_typeParamPrefix${node.name}'; + } + + @override + String visitWildcard(Wildcard node) { + // TODO(#141): Support wildcards + return super.visitWildcard(node); + } + + @override + String visitNonPrimitiveType(ReferredType node) { + return _jObject; + } +} + +class _TypeClass { + final String name; + final bool canBeConst; + + const _TypeClass(this.name, this.canBeConst); +} + +/// Generates the type class. +class _TypeClassGenerator extends TypeVisitor<_TypeClass> { + final bool isConst; + + /// Whether or not to return the equivalent boxed type class for primitives. + /// Only for interface implemetation. + final bool boxPrimitives; + + /// Whether or not to find the correct type variable from the static map. + /// Only for interface implemetation. + final bool typeVarFromMap; + + final Resolver resolver; + + _TypeClassGenerator( + this.resolver, { + this.isConst = true, + this.boxPrimitives = false, + this.typeVarFromMap = false, + }); + + @override + _TypeClass visitArrayType(ArrayType node) { + final innerTypeClass = node.type.accept(_TypeClassGenerator( + resolver, + isConst: false, + boxPrimitives: false, + typeVarFromMap: typeVarFromMap, + )); + final ifConst = innerTypeClass.canBeConst && isConst ? 'const ' : ''; + return _TypeClass( + '$ifConst${_jArray}Type(${innerTypeClass.name})', + innerTypeClass.canBeConst, + ); + } + + @override + _TypeClass visitDeclaredType(DeclaredType node) { + final allTypeParams = node.classDecl.allTypeParams + .accept(const _TypeParamGenerator(withExtends: false)) + .toList(); + + // The ones that are declared. + final definedTypeClasses = node.params.accept(_TypeClassGenerator( + resolver, + isConst: false, + boxPrimitives: false, + typeVarFromMap: typeVarFromMap, + )); + + // Can be const if all the type parameters are defined and each of them are + // also const. + final canBeConst = + allTypeParams.isEmpty || definedTypeClasses.every((e) => e.canBeConst); + + // Replacing the declared ones. They come at the end. + // The rest will be `JObjectType`. + if (allTypeParams.length >= node.params.length) { + allTypeParams.replaceRange( + 0, + allTypeParams.length - node.params.length, + List.filled( + allTypeParams.length - node.params.length, + // Adding const to subexpressions if the entire expression is not const. + '${canBeConst ? '' : 'const '}${_jObject}Type()', + ), + ); + allTypeParams.replaceRange( + allTypeParams.length - node.params.length, + allTypeParams.length, + // Adding const to subexpressions if the entire expression is not const. + definedTypeClasses.map((param) => + '${param.canBeConst && !canBeConst ? 'const ' : ''}${param.name}'), + ); + } + + final args = allTypeParams.join(', '); + final ifConst = isConst && canBeConst ? 'const ' : ''; + final prefix = resolver.resolvePrefix(node.classDecl); + return _TypeClass( + '$ifConst$prefix${node.classDecl.typeClassName}($args)', + canBeConst, + ); + } + + @override + _TypeClass visitPrimitiveType(PrimitiveType node) { + final ifConst = isConst ? 'const ' : ''; + final name = boxPrimitives ? 'J${node.boxedName}' : 'j${node.name}'; + return _TypeClass('$ifConst$_jni.${name}Type()', true); + } + + @override + _TypeClass visitTypeVar(TypeVar node) { + if (typeVarFromMap) { + return _TypeClass('_\$impls[\$p]!.${node.name}', false); + } + return _TypeClass(node.name, false); + } + + @override + _TypeClass visitWildcard(Wildcard node) { + // TODO(#141): Support wildcards + return super.visitWildcard(node); + } + + @override + _TypeClass visitNonPrimitiveType(ReferredType node) { + final ifConst = isConst ? 'const ' : ''; + return _TypeClass('$ifConst${_jObject}Type()', true); + } +} + +class _TypeParamGenerator extends Visitor { + final bool withExtends; + + const _TypeParamGenerator({required this.withExtends}); + + @override + String visit(TypeParam node) { + if (!withExtends) { + return node.name; + } + // TODO(#144): resolve the actual type being extended, if any. + return '$_typeParamPrefix${node.name} extends $_jObject'; + } +} + +class _JniResultGetter extends TypeVisitor { + const _JniResultGetter(); + + @override + String visitPrimitiveType(PrimitiveType node) { + if (node.name == 'void') return 'check()'; + if (node.name == 'double') return 'doubleFloat'; + if (node.name == 'int') return 'integer'; + return node.name; + } + + @override + String visitNonPrimitiveType(ReferredType node) { + return 'object'; + } +} + +/// Type signature for C-based bindings. +/// +/// When `isFFi` is `true`, it generates the ffi type signature and when it's +/// false, it generates the dart type signature. +/// +/// For example `ffi.Int32` is an ffi type signature while `int` is a Dart one: +/// ```dart +/// jniLookup>( +/// "sum") +/// .asFunction(); +/// ``` +class _TypeSig extends TypeVisitor { + final bool isFfi; + + const _TypeSig({required this.isFfi}); + + @override + String visitPrimitiveType(PrimitiveType node) { + if (isFfi) return '$_ffi.${node.ffiType}'; + if (node.name == 'boolean') return 'int'; + return node.dartType; + } + + @override + String visitNonPrimitiveType(ReferredType node) { + return _voidPointer; + } +} + +class _TypeName extends TypeVisitor { + const _TypeName(); + + @override + String visitPrimitiveType(PrimitiveType node) { + return node.name; + } + + @override + String visitNonPrimitiveType(ReferredType node) { + return 'object'; + } +} + +class _CallType extends TypeVisitor { + const _CallType(); + + @override + String visitPrimitiveType(PrimitiveType node) { + return '$_jCallType.${node.name}Type'; + } + + @override + String visitNonPrimitiveType(ReferredType node) { + return '$_jCallType.objectType'; + } +} + +class _ToNativeSuffix extends TypeVisitor { + const _ToNativeSuffix(); + + @override + String visitPrimitiveType(PrimitiveType node) { + if (node.name == 'boolean') { + return ' ? 1 : 0'; + } + return ''; + } + + @override + String visitNonPrimitiveType(ReferredType node) { + return '.$_selfPointer'; + } +} + +class _FromNative extends TypeVisitor { + final Resolver resolver; + final String value; + + const _FromNative(this.resolver, this.value); + + @override + String visitPrimitiveType(PrimitiveType node) { + return value; + } + + @override + String visitNonPrimitiveType(ReferredType node) { + final typeClass = node.accept(_TypeClassGenerator(resolver)).name; + return '$typeClass.fromRef($value)'; + } +} + +class _FieldGenerator extends Visitor { + final Config config; + final Resolver resolver; + final StringSink s; + + const _FieldGenerator(this.config, this.resolver, this.s); + + void writeCAccessor(Field node) { + final name = node.finalName; + final cName = node.accept(const CFieldName()); + final ifRef = node.isStatic ? '' : '$_jPointer, '; + + s.write(''' + static final _get_$name = + $_lookup<$_ffi.NativeFunction<$_jResult Function($ifRef)>>( + "get_$cName") + .asFunction<$_jResult Function($ifRef)>(); + +'''); + + if (!node.isFinal) { + final ffiSig = node.type.accept(const _TypeSig(isFfi: true)); + final dartSig = node.type.accept(const _TypeSig(isFfi: false)); + s.write(''' + static final _set_$name = + $_lookup<$_ffi.NativeFunction<$_jResult Function($ifRef$ffiSig)>>( + "set_$cName") + .asFunction<$_jResult Function($ifRef$dartSig)>(); + +'''); + } + } + + String cGetter(Field node) { + final name = node.finalName; + final getter = node.type.accept(const _JniResultGetter()); + final self = node.isStatic ? '' : _selfPointer; + return '_get_$name($self).$getter'; + } + + String cSetter(Field node) { + final name = node.finalName; + final self = node.isStatic ? '' : '$_selfPointer, '; + final toNativeSuffix = node.type.accept(const _ToNativeSuffix()); + return '_set_$name(${self}value$toNativeSuffix).check()'; + } + + void writeDartOnlyAccessor(Field node) { + final name = node.finalName; + final ifStatic = node.isStatic ? 'Static' : ''; + final descriptor = node.type.descriptor; + s.write(''' + static final _id_$name = + $_accessors.get${ifStatic}FieldIDOf( + $_classRef, + r"${node.name}", + r"$descriptor", + ); +'''); + } + + String dartOnlyGetter(Field node) { + final name = node.finalName; + final self = node.isStatic ? _classRef : _selfPointer; + final ifStatic = node.isStatic ? 'Static' : ''; + final callType = node.type.accept(const _CallType()); + final resultGetter = node.type.accept(const _JniResultGetter()); + return '$_accessors.get${ifStatic}Field($self, _id_$name, $callType)' + '.$resultGetter'; + } + + String dartOnlySetter(Field node) { + final name = node.finalName; + final self = node.isStatic ? _classRef : _selfPointer; + final ifStatic = node.isStatic ? 'Static' : ''; + final fieldType = node.type.accept(const _TypeName()).capitalize(); + final toNativeSuffix = node.type.accept(const _ToNativeSuffix()); + return '$_env.Set$ifStatic${fieldType}Field($self, _id_$name, value$toNativeSuffix)'; + } + + void writeDocs(Field node, {required bool writeReleaseInstructions}) { + final originalDecl = '${node.type.shorthand} ${node.name}'; + s.writeln(' /// from: ${node.modifiers.join(' ')} $originalDecl'); + if (node.type.kind != Kind.primitive && writeReleaseInstructions) { + s.writeln(_releaseInstruction); + } + node.javadoc?.accept(_DocGenerator(s, depth: 1)); + } + + @override + void visit(Field node) { + final isCBased = config.outputConfig.bindingsType == BindingsType.cBased; + + // Check if it should be a `static const` getter. + if (node.isFinal && node.isStatic && node.defaultValue != null) { + final name = node.finalName; + final value = node.defaultValue!; + // TODO(#31): Should we leave String as a normal getter instead? + if (value is String || value is num || value is bool) { + writeDocs(node, writeReleaseInstructions: false); + s.write(' static const $name = '); + if (value is String) { + s.write('r"""$value"""'); + } else { + s.write(value); + } + s.writeln(';\n'); + return; + } + } + + // Accessors. + (isCBased ? writeCAccessor : writeDartOnlyAccessor)(node); + + // Getter docs. + writeDocs(node, writeReleaseInstructions: true); + + final name = node.finalName; + final ifStatic = node.isStatic ? 'static ' : ''; + final type = node.type.accept(_TypeGenerator(resolver)); + s.write('$ifStatic$type get $name => '); + s.write(node.type.accept( + _FromNative(resolver, (isCBased ? cGetter : dartOnlyGetter)(node)), + )); + s.writeln(';\n'); + if (!node.isFinal) { + // Setter docs. + writeDocs(node, writeReleaseInstructions: true); + + s.write('${ifStatic}set $name($type value) => '); + s.write((isCBased ? cSetter : dartOnlySetter)(node)); + s.writeln(';\n'); + } + } +} + +class _MethodTypeSig extends Visitor { + final bool isFfi; + + const _MethodTypeSig({required this.isFfi}); + + @override + String visit(Method node) { + final args = [ + if (!node.isCtor && !node.isStatic) _voidPointer, + ...node.params.map((param) => param.type).accept( + _TypeSig(isFfi: isFfi), + ) + ].join(', '); + return '$_jResult Function($args)'; + } +} + +/// Generates Dart bindings for Java methods. +class _MethodGenerator extends Visitor { + final Config config; + final Resolver resolver; + final StringSink s; + + const _MethodGenerator(this.config, this.resolver, this.s); + + void writeCAccessor(Method node) { + final name = node.finalName; + final cName = node.accept(const CMethodName()); + final ffiSig = node.accept(const _MethodTypeSig(isFfi: true)); + final dartSig = node.accept(const _MethodTypeSig(isFfi: false)); + s.write(''' + static final _$name = + $_lookup<$_ffi.NativeFunction<$ffiSig>>("$cName") + .asFunction<$dartSig>(); + +'''); + } + + void writeDartOnlyAccessor(Method node) { + final name = node.finalName; + final ifStatic = node.isStatic ? 'Static' : ''; + final descriptor = node.descriptor; + s.write(''' + static final _id_$name = $_accessors.get${ifStatic}MethodIDOf( + $_classRef, r"${node.name}", r"$descriptor"); + +'''); + } + + bool isSuspendFun(Method node) { + return node.asyncReturnType != null; + } + + String cCtor(Method node) { + final name = node.finalName; + final params = + node.params.accept(const _ParamCall(isCBased: true)).join(', '); + return '_$name($params)'; + } + + String dartOnlyCtor(Method node) { + final name = node.finalName; + final params = + node.params.accept(const _ParamCall(isCBased: false)).join(', '); + return '$_accessors.newObjectWithArgs($_classRef, _id_$name, [$params])'; + } + + String cMethodCall(Method node) { + final name = node.finalName; + final params = [ + if (!node.isStatic) _selfPointer, + ...node.params.accept(const _ParamCall(isCBased: true)), + ].join(', '); + final resultGetter = node.returnType.accept(const _JniResultGetter()); + return '_$name($params).$resultGetter'; + } + + String dartOnlyMethodCall(Method node) { + final name = node.finalName; + final ifStatic = node.isStatic ? 'Static' : ''; + final self = node.isStatic ? _classRef : _selfPointer; + final callType = node.returnType.accept(const _CallType()); + final params = + node.params.accept(const _ParamCall(isCBased: false)).join(', '); + final resultGetter = node.returnType.accept(const _JniResultGetter()); + return '$_accessors.call${ifStatic}MethodWithArgs' + '($self, _id_$name, $callType, [$params]).$resultGetter'; + } + + @override + void visit(Method node) { + final isCBased = config.outputConfig.bindingsType == BindingsType.cBased; + + // Accessors + (isCBased ? writeCAccessor : writeDartOnlyAccessor)(node); + + // Docs + s.write(' /// from: '); + s.writeAll(node.modifiers.map((m) => '$m ')); + s.write('${node.returnType.shorthand} ${node.name}('); + s.writeAll(node.params.map((p) => '${p.type.shorthand} ${p.name}'), ', '); + s.writeln(')'); + if (node.returnType.kind != Kind.primitive || node.isCtor) { + s.writeln(_releaseInstruction); + } + node.javadoc?.accept(_DocGenerator(s, depth: 1)); + + // Used for inferring the type parameter from the given parameters. + final typeLocators = node.params + .accept(_ParamTypeLocator(resolver: resolver)) + .fold(>{}, _mergeMapValues).map( + (key, value) => MapEntry( + key, + _encloseIfNotEmpty( + '[', + value.delimited(', '), + ']', + ), + )); + + bool isRequired(TypeParam typeParam) { + return (typeLocators[typeParam.name] ?? '').isEmpty; + } + + final typeInference = + (node.isCtor ? node.classDecl.allTypeParams : node.typeParams) + .where((tp) => !isRequired(tp)) + .map((tp) => tp.name) + .map((tp) => '$tp ??= $_jni.lowestCommonSuperType' + '(${typeLocators[tp]}) as $_jType<$_typeParamPrefix$tp>;') + .join(_newLine(depth: 2)); + + if (node.isCtor) { + final className = node.classDecl.finalName; + final name = node.finalName; + final ctorName = name == 'new0' ? className : '$className.$name'; + final paramsDef = node.params.accept(_ParamDef(resolver)).delimited(', '); + final typeClassDef = _encloseIfNotEmpty( + '{', + node.classDecl.allTypeParams + .map((typeParam) => typeParam + .accept(_CtorTypeClassDef(isRequired: isRequired(typeParam)))) + .delimited(', '), + '}', + ); + final typeClassCall = node.classDecl.allTypeParams + .map((typeParam) => + typeParam.accept(const _TypeParamGenerator(withExtends: false))) + .delimited(', '); + + final ctorExpr = (isCBased ? cCtor : dartOnlyCtor)(node); + s.write(''' + factory $ctorName($paramsDef$typeClassDef) { + $typeInference + return ${node.classDecl.finalName}.fromRef( + $typeClassCall + $ctorExpr.object + ); + } + +'''); + return; + } + + final name = node.finalName; + final returnType = isSuspendFun(node) + ? 'Future<${node.asyncReturnType!.accept(_TypeGenerator(resolver))}>' + : node.returnType.accept(_TypeGenerator(resolver)); + final returnTypeClass = (node.asyncReturnType ?? node.returnType) + .accept(_TypeClassGenerator(resolver)) + .name; + final ifStatic = node.isStatic ? 'static ' : ''; + final defArgs = node.params.accept(_ParamDef(resolver)).toList(); + final typeClassDef = _encloseIfNotEmpty( + '{', + node.typeParams + .map((typeParam) => typeParam.accept(_MethodTypeClassDef( + isRequired: isRequired(typeParam), + ))) + .delimited(', '), + '}', + ); + final typeParamsDef = _encloseIfNotEmpty( + '<', + node.typeParams + .accept(const _TypeParamGenerator(withExtends: true)) + .join(', '), + '>', + ); + if (isSuspendFun(node)) { + defArgs.removeLast(); + } + final params = defArgs.delimited(', '); + s.write(' $ifStatic$returnType $name$typeParamsDef($params$typeClassDef)'); + final callExpr = (isCBased ? cMethodCall : dartOnlyMethodCall)(node); + if (isSuspendFun(node)) { + final returning = + node.asyncReturnType!.accept(_FromNative(resolver, '\$o')); + s.write('''async { + $typeInference + final \$p = ReceivePort(); + final \$c = $_jObject.fromRef($_protectedExtension.newPortContinuation(\$p)); + $callExpr; + final \$o = $_jPointer.fromAddress(await \$p.first); + final \$k = $returnTypeClass.getClass().reference; + if (!$_jni.Jni.env.IsInstanceOf(\$o, \$k)) { + throw "Failed"; + } + return $returning; + } + +'''); + } else { + final returning = node.returnType.accept(_FromNative(resolver, callExpr)); + s.writeln('''{ + $typeInference + return $returning; + } +'''); + } + } +} + +/// Generates the method type param definition. +/// +/// For example `required JObjType $T` in: +/// ```dart +/// void bar(..., {required JObjType $T}) => ... +/// ``` +class _MethodTypeClassDef extends Visitor { + final bool isRequired; + + const _MethodTypeClassDef({required this.isRequired}); + + @override + String visit(TypeParam node) { + return '${isRequired ? 'required ' : ''}$_jType' + '<$_typeParamPrefix${node.name}>${isRequired ? '' : '?'} ${node.name}'; + } +} + +/// Generates the class type param definition. Used only in constructors. +/// +/// For example `required this.$T` in: +/// ```dart +/// class Foo { +/// final JObjType $T; +/// Foo(..., {required this.$T}) => ... +/// } +/// ``` +class _CtorTypeClassDef extends Visitor { + final bool isRequired; + + const _CtorTypeClassDef({required this.isRequired}); + + @override + String visit(TypeParam node) { + return '${isRequired ? 'required ' : ''} $_jType' + '<$_typeParamPrefix${node.name}>${isRequired ? '' : '?'} ${node.name}'; + } +} + +/// Method parameter's definition. +/// +/// For example `Foo foo` in: +/// ```dart +/// void bar(Foo foo) => ... +/// ``` +class _ParamDef extends Visitor { + final Resolver resolver; + + const _ParamDef(this.resolver); + + @override + String visit(Param node) { + final type = node.type.accept(_TypeGenerator(resolver)); + return '$type ${node.finalName}'; + } +} + +/// Method parameter used in calling the native method. +/// +/// For example `foo.reference` in: +/// ```dart +/// void bar(Foo foo) => _bar(foo.reference); +/// ``` +class _ParamCall extends Visitor { + final bool isCBased; + + const _ParamCall({required this.isCBased}); + + @override + String visit(Param node) { + final nativeSuffix = node.type.accept(const _ToNativeSuffix()); + final paramCall = '${node.finalName}$nativeSuffix'; + if (!isCBased) { + // We need to wrap [paramCall] in the appropriate wrapper class. + return node.type.accept(_JValueWrapper(paramCall)); + } + return paramCall; + } +} + +/// Wraps the parameter in the appropriate JValue wrapper class. +/// +/// For instance, `int` in Dart can be mapped to `long` or `int` or ... in Java. +/// The wrapper class is how we identify the type in pure dart bindings. +class _JValueWrapper extends TypeVisitor { + final String param; + + _JValueWrapper(this.param); + + @override + String visitNonPrimitiveType(ReferredType node) { + return param; + } + + @override + String visitPrimitiveType(PrimitiveType node) { + if (node.name == 'long' || + node.name == 'double' || + node.name == 'boolean') { + return param; + } + return '$_jni.JValue${node.name.capitalize()}($param)'; + } +} + +/// A pair of [StringBuffer]s that can create an expression from the outer layer +/// inwards. +/// +/// For example: +/// ```dart +/// final buffer = OutsideInBuffer(); // asterisk (*) is used to show the middle +/// buffer.appendLeft('f('); // f(* +/// buffer.prependRight('x)'); // f(*x) +/// buffer.appendLeft('g('); // f(g(*x) +/// buffer.prependRight('y) + '); // f(g(*y) + x) +/// buffer.toString(); // f(g(y) + x) +/// ``` +@visibleForTesting +class OutsideInBuffer { + final StringBuffer _leftBuffer; + final StringBuffer _rightBuffer; + + OutsideInBuffer() + : _leftBuffer = StringBuffer(), + _rightBuffer = StringBuffer(); + + void prependRight(Object? object) { + final s = object.toString(); + for (var i = 0; i < s.length; ++i) { + _rightBuffer.write(s[s.length - i - 1]); + } + } + + void appendLeft(Object? object) { + _leftBuffer.write(object); + } + + @override + String toString() { + return _leftBuffer.toString() + _rightBuffer.toString().reversed; + } +} + +/// The ways to locate each type parameter. +/// +/// For example in `JArray> a`, `T` can be retreived using +/// ```dart +/// ((((a.$type as jni.JArrayType).elementType) as $JMapType).K) as jni.JObjType<$T> +/// ``` +/// and +/// ```dart +/// ((((a.$type as jni.JArrayType).elementType) as $JMapType).V) as jni.JObjType<$T> +/// ``` +class _ParamTypeLocator extends Visitor>> { + final Resolver resolver; + + _ParamTypeLocator({required this.resolver}); + + @override + Map> visit(Param node) { + return node.type.accept(_TypeVarLocator(resolver: resolver)).map( + (key, value) => MapEntry( + key, + value + .map((e) => + (e..appendLeft('${node.finalName}.\$type')).toString()) + .toList(), + ), + ); + } +} + +class _TypeVarLocator extends TypeVisitor>> { + final Resolver resolver; + + _TypeVarLocator({required this.resolver}); + + @override + Map> visitNonPrimitiveType(ReferredType node) { + return {}; + } + + @override + Map> visitWildcard(Wildcard node) { + // TODO(#141): Support wildcards + return super.visitWildcard(node); + } + + @override + Map> visitTypeVar(TypeVar node) { + return { + node.name: [ + OutsideInBuffer(), + ], + }; + } + + @override + Map> visitDeclaredType(DeclaredType node) { + if (node.classDecl.isObject) { + return {}; + } + final offset = node.classDecl.allTypeParams.length - node.params.length; + final result = >{}; + final prefix = resolver.resolvePrefix(node.classDecl); + final typeClass = '$prefix${node.classDecl.typeClassName}'; + for (var i = 0; i < node.params.length; ++i) { + final typeParam = node.classDecl.allTypeParams[i + offset].name; + final exprs = node.params[i].accept(this); + for (final expr in exprs.entries) { + for (final buffer in expr.value) { + buffer.appendLeft('('); + buffer.prependRight(' as $typeClass).$typeParam'); + result[expr.key] = (result[expr.key] ?? [])..add(buffer); + } + } + } + return result; + } + + @override + Map> visitArrayType(ArrayType node) { + final exprs = node.type.accept(this); + for (final e in exprs.values.expand((i) => i)) { + e.appendLeft('(('); + e.prependRight(' as ${_jArray}Type).elementType as $_jType)'); + } + return exprs; + } + + @override + Map> visitPrimitiveType(PrimitiveType node) { + return {}; + } +} + +/// Method defintion for Impl abstract class used for interface implementation. +class _AbstractImplMethod extends Visitor { + final Resolver resolver; + final StringSink s; + + _AbstractImplMethod(this.resolver, this.s); + + @override + void visit(Method node) { + final returnType = node.returnType.accept(_TypeGenerator(resolver)); + final name = node.finalName; + final args = node.params.accept(_ParamDef(resolver)).join(', '); + s.writeln(' $returnType $name($args);'); + } +} + +/// Closure defintion for concrete Impl class used for interface implementation. +class _ConcreteImplClosureDef extends Visitor { + final Resolver resolver; + final StringSink s; + + _ConcreteImplClosureDef(this.resolver, this.s); + + @override + void visit(Method node) { + final returnType = node.returnType.accept(_TypeGenerator(resolver)); + final name = node.finalName; + final args = node.params.accept(_ParamDef(resolver)).join(', '); + s.writeln(' final $returnType Function($args) _$name;'); + } +} + +/// Closure argument for concrete Impl class constructor. +/// Used for interface implementation. +class _ConcreteImplClosureCtorArg extends Visitor { + final Resolver resolver; + + _ConcreteImplClosureCtorArg(this.resolver); + + @override + String visit(Method node) { + final returnType = node.returnType.accept(_TypeGenerator(resolver)); + final name = node.finalName; + final args = node.params.accept(_ParamDef(resolver)).join(', '); + return 'required $returnType Function($args) $name,'; + } +} + +/// Method defintion for concrete Impl class used for interface implementation. +class _ConcreteImplMethod extends Visitor { + final Resolver resolver; + final StringSink s; + + _ConcreteImplMethod(this.resolver, this.s); + + @override + void visit(Method node) { + final returnType = node.returnType.accept(_TypeGenerator(resolver)); + final name = node.finalName; + final argsDef = node.params.accept(_ParamDef(resolver)).join(', '); + final argsCall = node.params.map((param) => param.finalName).join(', '); + s.write(''' + $returnType $name($argsDef) { + return _$name($argsCall); + }'''); + } +} + +/// The if statement to check which method has been called from the proxy class. +class _InterfaceMethodIf extends Visitor { + final Resolver resolver; + final StringSink s; + + _InterfaceMethodIf(this.resolver, this.s); + + @override + void visit(Method node) { + final isVoid = node.returnType.name == 'void'; + final signature = node.javaSig; + final saveResult = isVoid ? '' : 'final \$r = '; + final name = node.finalName; + s.write(''' + if (\$d == r"$signature") { + ${saveResult}_\$impls[\$p]!.$name( +'''); + for (var i = 0; i < node.params.length; ++i) { + node.params[i].accept(_InterfaceParamCast(resolver, s, paramIndex: i)); + } + const returnBox = _InterfaceReturnBox(); + s.write(''' + ); + return ${node.returnType.accept(returnBox)}; + } +'''); + } +} + +/// Generates casting to the correct parameter type from the list of JObject +/// arguments received from the call to the proxy class. +class _InterfaceParamCast extends Visitor { + final Resolver resolver; + final StringSink s; + final int paramIndex; + + _InterfaceParamCast( + this.resolver, + this.s, { + required this.paramIndex, + }); + + @override + void visit(Param node) { + final typeClass = node.type + .accept(_TypeClassGenerator( + resolver, + boxPrimitives: true, + typeVarFromMap: true, + )) + .name; + s.write('\$a[$paramIndex].castTo($typeClass, releaseOriginal: true)'); + if (node.type.kind == Kind.primitive) { + // Convert to Dart type. + final name = (node.type.type as PrimitiveType).name; + s.write('.${name}Value(releaseOriginal: true)'); + } + s.writeln(','); + } +} + +/// Boxes the returned primitive value into the correct Boxed type. +/// Only returns the reference for non primitive types. +/// Returns null for void. +/// +/// Since Dart doesn't know that this global reference is still used, it might +/// garbage collect it via [NativeFinalizer] thus making it invalid. +/// This passes the ownership to Java using [setAsReleased]. +/// +/// `toPointer` detaches the object from the [NativeFinalizer] and Java +/// will clean up the global reference afterwards. +/// +/// For example `$r.toJInteger().toPointer()` when the return +/// type is `integer`. +class _InterfaceReturnBox extends TypeVisitor { + const _InterfaceReturnBox(); + + @override + String visitNonPrimitiveType(ReferredType node) { + // Casting is done to create a new global reference. The user might + // use the original reference elsewhere and so the original object + // should not be [setAsReleased]. + return '(\$r as $_jObject).castTo(const ${_jObject}Type()).toPointer()'; + } + + @override + String visitPrimitiveType(PrimitiveType node) { + if (node.name == 'void') { + return '$_jni.nullptr'; + } + return '$_jni.J${node.boxedName}(\$r).toPointer()'; + } +} diff --git a/pkgs/jnigen/lib/src/bindings/descriptor.dart b/pkgs/jnigen/lib/src/bindings/descriptor.dart new file mode 100644 index 000000000..f7d774ae0 --- /dev/null +++ b/pkgs/jnigen/lib/src/bindings/descriptor.dart @@ -0,0 +1,115 @@ +import '../elements/elements.dart'; +import 'visitor.dart'; + +/// Adds the type and method descriptor to all methods in all of the classes. +/// +/// ASM already fills the descriptor field for methods but doclet does not. +class Descriptor extends Visitor { + const Descriptor(); + + @override + void visit(Classes node) { + for (final classDecl in node.decls.values) { + classDecl.accept(const _ClassDescriptor()); + } + } +} + +class _ClassDescriptor extends Visitor { + const _ClassDescriptor(); + + @override + void visit(ClassDecl node) { + final methodDescriptor = MethodDescriptor(node.allTypeParams); + for (final method in node.methods) { + method.descriptor ??= method.accept(methodDescriptor); + } + final typeDescriptor = TypeDescriptor(node.allTypeParams); + for (final field in node.fields) { + field.type.descriptor = field.type.accept(typeDescriptor); + } + for (final interface in node.interfaces) { + interface.descriptor = interface.accept(typeDescriptor); + } + } +} + +/// Generates JNI Method descriptor. +/// +/// https://docs.oracle.com/en/java/javase/18/docs/specs/jni/types.html#type-signatures +/// Also see: [TypeDescriptor] +class MethodDescriptor extends Visitor { + final List typeParams; + + MethodDescriptor(this.typeParams); + + @override + String visit(Method node) { + final s = StringBuffer(); + final typeParamsIncludingThis = [...typeParams, ...node.typeParams]; + final typeDescriptor = TypeDescriptor(typeParamsIncludingThis); + s.write('('); + for (final param in node.params) { + final desc = param.type.accept(typeDescriptor); + param.type.descriptor = desc; + s.write(desc); + } + s.write(')'); + final returnTypeDesc = + node.returnType.accept(TypeDescriptor(typeParamsIncludingThis)); + node.returnType.descriptor = returnTypeDesc; + s.write(returnTypeDesc); + return s.toString(); + } +} + +/// JVM representation of type signatures. +/// +/// https://docs.oracle.com/en/java/javase/18/docs/specs/jni/types.html#type-signatures +class TypeDescriptor extends TypeVisitor { + final List typeParams; + + TypeDescriptor(this.typeParams); + + @override + String visitArrayType(ArrayType node) { + final inner = node.type.accept(this); + return '[$inner'; + } + + @override + String visitDeclaredType(DeclaredType node) { + final internalName = node.binaryName.replaceAll('.', '/'); + return 'L$internalName;'; + } + + @override + String visitPrimitiveType(PrimitiveType node) { + return node.signature; + } + + @override + String visitTypeVar(TypeVar node) { + final typeParam = typeParams.lastWhere( + (typeParam) => typeParam.name == node.name, + orElse: () { + print('${node.name} was not found!'); + throw 'error'; + }, + ); + return typeParam.bounds.isEmpty + ? super.visitTypeVar(node) + : typeParam.bounds.first.accept(this); + } + + @override + String visitWildcard(Wildcard node) { + final extendsBound = node.extendsBound?.accept(this); + return extendsBound ?? super.visitWildcard(node); + } + + @override + String visitNonPrimitiveType(ReferredType node) { + return 'Ljava/lang/Object;'; + } +} diff --git a/pkgs/jnigen/lib/src/bindings/excluder.dart b/pkgs/jnigen/lib/src/bindings/excluder.dart new file mode 100644 index 000000000..1568bd3ec --- /dev/null +++ b/pkgs/jnigen/lib/src/bindings/excluder.dart @@ -0,0 +1,61 @@ +// Copyright (c) 2023, 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. + +import '../config/config.dart'; +import '../elements/elements.dart'; +import '../logging/logging.dart'; +import 'visitor.dart'; + +bool _isPrivate(ClassMember classMember) => + !classMember.isPublic && !classMember.isProtected; + +class Excluder extends Visitor { + final Config config; + + const Excluder(this.config); + + @override + void visit(Classes node) { + node.decls.removeWhere((_, classDecl) { + final excluded = _isPrivate(classDecl) || + !(config.exclude?.classes?.included(classDecl) ?? true); + if (excluded) { + log.fine('Excluded class ${classDecl.binaryName}'); + } + return excluded; + }); + final classExcluder = _ClassExcluder(config); + for (final classDecl in node.decls.values) { + classDecl.accept(classExcluder); + } + } +} + +class _ClassExcluder extends Visitor { + final Config config; + + _ClassExcluder(this.config); + + @override + void visit(ClassDecl node) { + node.methods = node.methods.where((method) { + final included = !_isPrivate(method) && + !method.name.startsWith('_') && + (config.exclude?.methods?.included(node, method) ?? true); + if (!included) { + log.fine('Excluded method ${node.binaryName}#${method.name}'); + } + return included; + }).toList(); + node.fields = node.fields.where((field) { + final included = !_isPrivate(field) && + !field.name.startsWith('_') && + (config.exclude?.fields?.included(node, field) ?? true); + if (!included) { + log.fine('Excluded field ${node.binaryName}#${field.name}'); + } + return included; + }).toList(); + } +} diff --git a/pkgs/jnigen/lib/src/bindings/kotlin_processor.dart b/pkgs/jnigen/lib/src/bindings/kotlin_processor.dart new file mode 100644 index 000000000..4a48aa8c5 --- /dev/null +++ b/pkgs/jnigen/lib/src/bindings/kotlin_processor.dart @@ -0,0 +1,60 @@ +// Copyright (c) 2023, 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. + +import '../elements/elements.dart'; +import 'visitor.dart'; + +/// A [Visitor] that adds the the information from Kotlin's metadata to the Java +/// classes and methods. +class KotlinProcessor extends Visitor { + @override + void visit(Classes node) { + final classProcessor = _KotlinClassProcessor(); + for (final classDecl in node.decls.values) { + classDecl.accept(classProcessor); + } + } +} + +class _KotlinClassProcessor extends Visitor { + @override + void visit(ClassDecl node) { + if (node.kotlinClass == null) { + return; + } + // This [ClassDecl] is actually a Kotlin class. + // Matching methods and functions from the metadata. + final functions = {}; + for (final function in node.kotlinClass!.functions) { + final signature = function.name + function.descriptor; + functions[signature] = function; + } + for (final method in node.methods) { + final signature = method.name + method.descriptor!; + if (functions.containsKey(signature)) { + method.accept(_KotlinMethodProcessor(functions[signature]!)); + } + } + } +} + +class _KotlinMethodProcessor extends Visitor { + final KotlinFunction function; + + _KotlinMethodProcessor(this.function); + + @override + void visit(Method node) { + if (function.isSuspend) { + const kotlinContinutationType = 'kotlin.coroutines.Continuation'; + assert(node.params.isNotEmpty && + node.params.last.type.kind == Kind.declared && + node.params.last.type.name == kotlinContinutationType); + final continuationType = node.params.last.type.type as DeclaredType; + node.asyncReturnType = continuationType.params.isEmpty + ? TypeUsage.object + : continuationType.params.first; + } + } +} diff --git a/pkgs/jnigen/lib/src/bindings/linker.dart b/pkgs/jnigen/lib/src/bindings/linker.dart new file mode 100644 index 000000000..8e9091028 --- /dev/null +++ b/pkgs/jnigen/lib/src/bindings/linker.dart @@ -0,0 +1,203 @@ +// Copyright (c) 2023, 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. + +import '../config/config.dart'; +import '../elements/elements.dart'; +import '../logging/logging.dart'; +import 'visitor.dart'; + +typedef _Resolver = ClassDecl Function(String? binaryName); + +/// A [Visitor] that adds the correct [ClassDecl] references from the +/// string binary names. +/// +/// It adds the following references: +/// * Links [ClassDecl] objects from imported dependencies. +/// * Adds references from child elements back to their parent elements. +/// * Resolves Kotlin specific `asyncReturnType` for methods. +class Linker extends Visitor> { + Linker(this.config); + + final Config config; + + @override + Future visit(Classes node) async { + // Specify paths for this package's classes. + final root = config.outputConfig.dartConfig.path; + if (config.outputConfig.dartConfig.structure == + OutputStructure.singleFile) { + // Connect all to the root if the output is in single file mode. + final path = root.toFilePath(); + for (final decl in node.decls.values) { + decl.path = path; + } + } else { + for (final decl in node.decls.values) { + final dollarSign = decl.binaryName.indexOf('\$'); + final className = dollarSign != -1 + ? decl.binaryName.substring(0, dollarSign) + : decl.binaryName; + final path = className.replaceAll('.', '/'); + decl.path = root.resolve(path).toFilePath(); + } + } + + // Find all the imported classes. + await config.importClasses(); + + if (config.importedClasses.keys + .toSet() + .intersection(node.decls.keys.toSet()) + .isNotEmpty) { + log.fatal( + 'Trying to re-import the generated classes.\n' + 'Try hiding the class(es) in import.', + ); + } + + for (final className in config.importedClasses.keys) { + log.finest('Imported $className successfully.'); + } + + ClassDecl resolve(String? binaryName) { + return config.importedClasses[binaryName] ?? + node.decls[binaryName] ?? + resolve(TypeUsage.object.name); + } + + final classLinker = _ClassLinker( + config, + resolve, + ); + for (final classDecl in node.decls.values) { + classDecl.accept(classLinker); + } + } +} + +class _ClassLinker extends Visitor { + final Config config; + final _Resolver resolve; + final Set _linked; + + _ClassLinker( + this.config, + this.resolve, + ) : _linked = {...config.importedClasses.values}; + + @override + void visit(ClassDecl node) { + if (_linked.contains(node)) return; + log.finest('Linking ${node.binaryName}.'); + _linked.add(node); + + node.parent = node.parentName == null ? null : resolve(node.parentName); + + final typeLinker = _TypeLinker(resolve); + node.superclass ??= TypeUsage.object; + node.superclass!.type.accept(typeLinker); + final superclass = (node.superclass!.type as DeclaredType).classDecl; + superclass.accept(this); + + node.superCount = superclass.superCount + 1; + + final fieldLinker = _FieldLinker(typeLinker); + for (final field in node.fields) { + field.classDecl = node; + field.accept(fieldLinker); + } + final methodLinker = _MethodLinker(config, typeLinker); + for (final method in node.methods) { + method.classDecl = node; + method.accept(methodLinker); + } + node.interfaces.accept(typeLinker).toList(); + node.typeParams.accept(_TypeParamLinker(typeLinker)).toList(); + } +} + +class _MethodLinker extends Visitor { + _MethodLinker(this.config, this.typeVisitor); + + final Config config; + final TypeVisitor typeVisitor; + + @override + void visit(Method node) { + node.returnType.accept(typeVisitor); + final typeParamLinker = _TypeParamLinker(typeVisitor); + final paramLinker = _ParamLinker(typeVisitor); + node.typeParams.accept(typeParamLinker).toList(); + node.params.accept(paramLinker).toList(); + node.asyncReturnType?.accept(typeVisitor); + } +} + +class _TypeLinker extends TypeVisitor { + const _TypeLinker(this.resolve); + + final _Resolver resolve; + + @override + void visitDeclaredType(DeclaredType node) { + node.params.accept(this).toList(); + node.classDecl = resolve(node.binaryName); + } + + @override + void visitWildcard(Wildcard node) { + node.superBound?.type.accept(this); + node.extendsBound?.type.accept(this); + } + + @override + void visitArrayType(ArrayType node) { + node.type.accept(this); + } + + @override + void visitPrimitiveType(PrimitiveType node) { + // Do nothing + } + + @override + void visitNonPrimitiveType(ReferredType node) { + // Do nothing + } +} + +class _FieldLinker extends Visitor { + _FieldLinker(this.typeVisitor); + + final TypeVisitor typeVisitor; + + @override + void visit(Field node) { + node.type.accept(typeVisitor); + } +} + +class _TypeParamLinker extends Visitor { + _TypeParamLinker(this.typeVisitor); + + final TypeVisitor typeVisitor; + + @override + void visit(TypeParam node) { + for (final bound in node.bounds) { + bound.accept(typeVisitor); + } + } +} + +class _ParamLinker extends Visitor { + _ParamLinker(this.typeVisitor); + + final TypeVisitor typeVisitor; + + @override + void visit(Param node) { + node.type.accept(typeVisitor); + } +} diff --git a/pkgs/jnigen/lib/src/bindings/renamer.dart b/pkgs/jnigen/lib/src/bindings/renamer.dart new file mode 100644 index 000000000..56fea0aed --- /dev/null +++ b/pkgs/jnigen/lib/src/bindings/renamer.dart @@ -0,0 +1,261 @@ +// Copyright (c) 2023, 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. + +import '../config/config.dart'; +import '../elements/elements.dart'; +import '../logging/logging.dart'; +import 'visitor.dart'; + +const Set _keywords = { + 'abstract', + 'as', + 'assert', + 'async', + 'await', + 'break', + 'case', + 'catch', + 'class', + 'const', + 'continue', + 'covariant', + 'default', + 'deferred', + 'do', + 'dynamic', + 'else', + 'enum', + 'export', + 'extends', + 'extension', + 'external', + 'factory', + 'false', + 'final', + 'finally', + 'for', + 'Function', + 'get', + 'hide', + 'if', + 'implements', + 'import', + 'in', + 'interface', + 'is', + 'late', + 'library', + 'mixin', + 'new', + 'null', + 'on', + 'operator', + 'part', + 'required', + 'rethrow', + 'return', + 'set', + 'show', + 'static', + 'super', + 'switch', + 'sync', + 'this', + 'throw', + 'true', + 'try', + 'type', // Is used for type classes. + 'typedef', + 'var', + 'void', + 'while', + 'with', + 'yield', +}; + +/// Methods & properties already defined by dart JObject base class. +const Map _definedSyms = { + 'equals': 1, + 'toString': 1, + 'hashCode': 1, + 'runtimeType': 1, + 'noSuchMethod': 1, + 'reference': 1, + 'isReleased': 1, + 'isNull': 1, + 'use': 1, + 'release': 1, + 'releasedBy': 1, + 'getFieldID': 1, + 'getStaticFieldID': 1, + 'getMethodID': 1, + 'getStaticMethodID': 1, + 'getField': 1, + 'getFieldByName': 1, + 'getStaticField': 1, + 'getStaticFieldByName': 1, + 'callMethod': 1, + 'callMethodByName': 1, + 'callStaticMethod': 1, + 'callStaticMethodByName': 1, +}; + +/// Appends 0 to [name] if [name] is a keyword. +/// +/// Examples: +/// * `int` -> `int0` +/// * `i` -> `i` +String _keywordRename(String name) => + _keywords.contains(name) ? '${name}0' : name; + +String _renameConflict(Map counts, String name) { + if (counts.containsKey(name)) { + final count = counts[name]!; + final renamed = '$name$count'; + counts[name] = count + 1; + return renamed; + } + counts[name] = 1; + return _keywordRename(name); +} + +class Renamer implements Visitor { + final Config config; + + Renamer(this.config); + + @override + void visit(Classes node) { + final classRenamer = _ClassRenamer(config); + + for (final classDecl in node.decls.values) { + classDecl.accept(classRenamer); + } + } +} + +class _ClassRenamer implements Visitor { + final Config config; + final Set renamed; + final Map classNameCounts = {}; + final Map> nameCounts = {}; + + _ClassRenamer( + this.config, + ) : renamed = {...config.importedClasses.values}; + + /// Returns class name as useful in dart. + /// + /// Eg -> a.b.X.Y -> X_Y + static String _getSimplifiedClassName(String binaryName) => + binaryName.split('.').last.replaceAll('\$', '_'); + + @override + void visit(ClassDecl node) { + if (renamed.contains(node)) return; + log.finest('Renaming ${node.binaryName}.'); + renamed.add(node); + + nameCounts[node] = {..._definedSyms}; + node.methodNumsAfterRenaming = {}; + + final className = _getSimplifiedClassName(node.binaryName); + node.uniqueName = _renameConflict(classNameCounts, className); + + // When generating all the classes in a single file + // the names need to be unique. + final uniquifyName = + config.outputConfig.dartConfig.structure == OutputStructure.singleFile; + node.finalName = uniquifyName ? node.uniqueName : className; + // TODO(#143): $ at the beginning is a temporary fix for the name collision. + node.typeClassName = '\$${node.finalName}Type'; + log.fine('Class ${node.binaryName} is named ${node.finalName}'); + + final superClass = (node.superclass!.type as DeclaredType).classDecl; + superClass.accept(this); + nameCounts[node]!.addAll(nameCounts[superClass] ?? {}); + final methodRenamer = _MethodRenamer( + config, + nameCounts[node]!, + ); + for (final method in node.methods) { + method.accept(methodRenamer); + } + + final fieldRenamer = _FieldRenamer(config, nameCounts[node]!); + for (final field in node.fields) { + field.accept(fieldRenamer); + } + } +} + +class _MethodRenamer implements Visitor { + _MethodRenamer(this.config, this.nameCounts); + + final Config config; + final Map nameCounts; + + @override + void visit(Method node) { + final name = node.name == '' ? 'new' : node.name; + final sig = node.javaSig; + // If node is in super class, assign its number, overriding it. + final superClass = + (node.classDecl.superclass!.type as DeclaredType).classDecl; + final superNum = superClass.methodNumsAfterRenaming[sig]; + if (superNum != null) { + // Don't rename if superNum == 0 + // Unless the node name is a keyword. + final superNumText = superNum == 0 ? '' : '$superNum'; + final methodName = superNum == 0 ? _keywordRename(name) : name; + node.finalName = '$methodName$superNumText'; + node.classDecl.methodNumsAfterRenaming[sig] = superNum; + } else { + node.finalName = _renameConflict(nameCounts, name); + node.classDecl.methodNumsAfterRenaming[sig] = nameCounts[name]! - 1; + } + log.fine('Method ${node.classDecl.binaryName}#${node.name}' + ' is named ${node.finalName}'); + + final paramRenamer = _ParamRenamer(config); + for (final param in node.params) { + param.accept(paramRenamer); + } + + // Kotlin specific + if (node.asyncReturnType != null) { + // It's a suspend fun so the continuation parameter + // should be named $c instead + node.params.last.finalName = '\$c'; + } + } +} + +class _FieldRenamer implements Visitor { + _FieldRenamer(this.config, this.nameCounts); + + final Config config; + final Map nameCounts; + + @override + void visit(Field node) { + node.finalName = _renameConflict( + nameCounts, + node.name, + ); + log.fine('Field ${node.classDecl.binaryName}#${node.name}' + ' is named ${node.finalName}'); + } +} + +class _ParamRenamer implements Visitor { + _ParamRenamer(this.config); + + final Config config; + + @override + void visit(Param node) { + node.finalName = _keywordRename(node.name); + } +} diff --git a/pkgs/jnigen/lib/src/bindings/resolver.dart b/pkgs/jnigen/lib/src/bindings/resolver.dart new file mode 100644 index 000000000..68b250b78 --- /dev/null +++ b/pkgs/jnigen/lib/src/bindings/resolver.dart @@ -0,0 +1,153 @@ +// Copyright (c) 2023, 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. + +import 'dart:math'; + +import '../elements/elements.dart'; +import '../logging/logging.dart'; + +class Resolver { + /// Class corresponding to currently writing file. + /// + /// Is [null] when in single file mode. + final String? currentClass; + + /// Explicit import mappings. + final Map importedClasses; + + /// Names of all classes in input. + final Set inputClassNames; + + final List importStrings = []; + + final Set _relativeImportedClasses = {}; + final Map _importedNameToClass = {}; + final Map _classToImportedName = {}; + + Resolver({ + required this.importedClasses, + required this.currentClass, + this.inputClassNames = const {}, + }); + + static String getFileClassName(String binaryName) { + final dollarSign = binaryName.indexOf('\$'); + if (dollarSign != -1) { + return binaryName.substring(0, dollarSign); + } + return binaryName; + } + + /// splits [str] into 2 from last occurence of [sep] + static List cutFromLast(String str, String sep) { + final li = str.lastIndexOf(sep); + if (li == -1) { + return ['', str]; + } + return [str.substring(0, li), str.substring(li + 1)]; + } + + /// Get the prefix for the class + String resolvePrefix(ClassDecl classDecl) { + if (classDecl.path == 'package:jni/jni.dart') { + // For package:jni we don't use a leading underscore. + return 'jni.'; + } + final binaryName = classDecl.binaryName; + final target = getFileClassName(binaryName); + + // For classes we generate (inside [inputClassNames]) no import + // (and therefore no prefix) is necessary when: + // * Never necessary in single file mode + // * In multi file mode if the target is the same as the current class + if ((currentClass == null || target == currentClass) && + inputClassNames.contains(binaryName)) { + return ''; + } + + if (_classToImportedName.containsKey(target)) { + // This package was already resolved + // but we still need to check if it was a relative import, in which case + // the class not in inputClassNames cannot be mapped here. + if (!_relativeImportedClasses.contains(target) || + inputClassNames.contains(binaryName)) { + final importedName = _classToImportedName[target]; + return '$importedName.'; + } + } + + final classImport = getImport(target, binaryName); + log.finest('$target resolved to $classImport for $binaryName'); + if (classImport == null) { + return ''; + } + + final pkgName = cutFromLast(target, '.')[1].toLowerCase(); + if (pkgName.isEmpty) { + throw UnsupportedError('No package could be deduced from ' + 'qualified binaryName'); + } + + // We always name imports with an underscore suffix, so that they can be + // never shadowed by a parameter or local variable. + var importedName = '${pkgName}_'; + int suffix = 0; + while (_importedNameToClass.containsKey(importedName)) { + suffix++; + importedName = '$pkgName${suffix}_'; + } + + _importedNameToClass[importedName] = target; + _classToImportedName[target] = importedName; + importStrings.add('import "$classImport" as $importedName;\n'); + return '$importedName.'; + } + + /// Returns import string for [classToResolve], or `null` if the class is not + /// found. + /// + /// [binaryName] is the class name trying to be resolved. This parameter is + /// requested so that classes included in current bindings can be resolved + /// using relative path. + String? getImport(String classToResolve, String binaryName) { + final prefix = classToResolve; + + // short circuit if the requested class is specified directly in import map. + if (importedClasses.containsKey(binaryName)) { + return importedClasses[binaryName]!.path; + } + + if (prefix.isEmpty) { + throw UnsupportedError('unexpected: empty package name.'); + } + + final dest = classToResolve.split('.'); + final src = currentClass!.split('.'); + // Use relative import when the required class is included in current set + // of bindings. + if (inputClassNames.contains(binaryName)) { + int common = 0; + // find the common prefix path directory of current package, and directory + // of target package + // src.length - 1 simply corresponds to directory of the package. + for (int i = 0; i < src.length - 1 && i < dest.length - 1; i++) { + if (src[i] == dest[i]) { + common++; + } else { + break; + } + } + final pathToCommon = '../' * ((src.length - 1) - common); + final pathToClass = dest.sublist(max(common, 0)).join('/'); + _relativeImportedClasses.add(classToResolve); + return '$pathToCommon$pathToClass.dart'; + } + + return null; + } + + List getImportStrings() { + return importStrings; + } +} diff --git a/pkgs/jnigen/lib/src/bindings/unnester.dart b/pkgs/jnigen/lib/src/bindings/unnester.dart new file mode 100644 index 000000000..d9323df91 --- /dev/null +++ b/pkgs/jnigen/lib/src/bindings/unnester.dart @@ -0,0 +1,90 @@ +// Copyright (c) 2023, 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. + +import '../elements/elements.dart'; +import 'visitor.dart'; + +/// A [Visitor] that processes nested classes. +/// +/// Nested classes are not supported in Dart. So this "unnests" them into +/// separate classes. +class Unnester extends Visitor { + const Unnester(); + + @override + void visit(node) { + final classProcessor = _ClassUnnester(); + for (final classDecl in node.decls.values) { + classDecl.accept(classProcessor); + } + } +} + +class _ClassUnnester extends Visitor { + final processed = {}; + + @override + void visit(ClassDecl node) { + if (processed.contains(node)) return; + processed.add(node); + // We need to visit the ancestors first. + node.parent?.accept(this); + + // Add type params of outer classes to the nested classes. + final allTypeParams = []; + if (!node.isStatic) { + allTypeParams.addAll(node.parent?.allTypeParams ?? []); + } + allTypeParams.addAll(node.typeParams); + node.allTypeParams = allTypeParams; + + if (node.isNested && !node.isStatic) { + const methodProcessor = _MethodUnnester(); + for (final method in node.methods) { + method.accept(methodProcessor); + } + } + } +} + +class _MethodUnnester extends Visitor { + const _MethodUnnester(); + + @override + void visit(Method node) { + assert(!node.classDecl.isStatic); + assert(node.classDecl.isNested); + // TODO(#319): Unnest the methods in APISummarizer itself. + // For now the nullity of [node.descriptor] identifies if the doclet + // backend was used and the method would potentially need "unnesting". + if ((node.isCtor || node.isStatic) && node.descriptor == null) { + // Non-static nested classes take an instance of their outer class as the + // first parameter. + // + // This is not accounted for by the **doclet** summarizer, so we + // manually add it as the first parameter. + final parentTypeParamCount = node.classDecl.allTypeParams.length - + node.classDecl.typeParams.length; + final parentTypeParams = [ + for (final typeParam + in node.classDecl.allTypeParams.take(parentTypeParamCount)) ...[ + TypeUsage( + shorthand: typeParam.name, kind: Kind.typeVariable, typeJson: {}) + ..type = TypeVar(name: typeParam.name), + ] + ]; + final parentType = DeclaredType( + binaryName: node.classDecl.parent!.binaryName, + params: parentTypeParams, + )..classDecl = node.classDecl.parent!; + final parentTypeUsage = TypeUsage( + shorthand: parentType.binaryName, kind: Kind.declared, typeJson: {}) + ..type = parentType; + final param = Param(name: '\$parent', type: parentTypeUsage); + // Make the list modifiable. + if (node.params.isEmpty) node.params = []; + node.params.insert(0, param); + } + } +} diff --git a/pkgs/jnigen/lib/src/bindings/visitor.dart b/pkgs/jnigen/lib/src/bindings/visitor.dart new file mode 100644 index 000000000..417180c85 --- /dev/null +++ b/pkgs/jnigen/lib/src/bindings/visitor.dart @@ -0,0 +1,36 @@ +// Copyright (c) 2023, 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. + +import '../elements/elements.dart'; + +abstract class Visitor, R> { + const Visitor(); + + R visit(T node); +} + +abstract class TypeVisitor { + const TypeVisitor(); + + R visitNonPrimitiveType(ReferredType node); + R visitPrimitiveType(PrimitiveType node); + R visitArrayType(ArrayType node) => visitNonPrimitiveType(node); + R visitDeclaredType(DeclaredType node) => visitNonPrimitiveType(node); + R visitTypeVar(TypeVar node) => visitNonPrimitiveType(node); + R visitWildcard(Wildcard node) => visitNonPrimitiveType(node); +} + +extension MultiVisitor> on Iterable> { + /// Accepts all lazily. Remember to call `.toList()` or similar methods! + Iterable accept(Visitor v) { + return map((e) => e.accept(v)); + } +} + +extension MultiTypeUsageVisitor on Iterable { + /// Accepts all lazily. Remember to call `.toList()` or similar methods! + Iterable accept(TypeVisitor v) { + return map((e) => e.type.accept(v)); + } +} diff --git a/pkgs/jnigen/lib/src/config/config.dart b/pkgs/jnigen/lib/src/config/config.dart new file mode 100644 index 000000000..c4168d86b --- /dev/null +++ b/pkgs/jnigen/lib/src/config/config.dart @@ -0,0 +1,6 @@ +// 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. + +export 'config_types.dart'; +export 'config_exception.dart'; diff --git a/pkgs/jnigen/lib/src/config/config_exception.dart b/pkgs/jnigen/lib/src/config/config_exception.dart new file mode 100644 index 000000000..d3518cc15 --- /dev/null +++ b/pkgs/jnigen/lib/src/config/config_exception.dart @@ -0,0 +1,12 @@ +// 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. + +/// Exception thrown when a configuration value is invalid. +class ConfigException implements Exception { + ConfigException(this.message); + String message; + + @override + String toString() => 'Error parsing configuration: $message'; +} diff --git a/pkgs/jnigen/lib/src/config/config_types.dart b/pkgs/jnigen/lib/src/config/config_types.dart new file mode 100644 index 000000000..02dcbc2ea --- /dev/null +++ b/pkgs/jnigen/lib/src/config/config_types.dart @@ -0,0 +1,703 @@ +// 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. + +import 'dart:io'; + +import 'package:logging/logging.dart'; +import 'package:path/path.dart' as p; +import 'package:pub_semver/pub_semver.dart'; +import 'package:yaml/yaml.dart'; + +import '../elements/elements.dart'; +import '../logging/logging.dart'; +import '../util/find_package.dart'; +import 'config_exception.dart'; +import 'experiments.dart'; +import 'filters.dart'; +import 'yaml_reader.dart'; + +/// Modify this when symbols file format changes according to pub_semver. +final _currentVersion = Version(1, 0, 0); + +/// Configuration for dependencies to be downloaded using maven. +/// +/// Dependency names should be listed in groupId:artifactId:version format. +/// For [sourceDeps], sources will be unpacked to [sourceDir] root and JAR files +/// will also be downloaded. For the packages in jarOnlyDeps, only JAR files +/// will be downloaded. +/// +/// When passed as a parameter to [Config], the downloaded sources and +/// JAR files will be automatically added to source path and class path +/// respectively. +class MavenDownloads { + static const defaultMavenSourceDir = 'mvn_java'; + static const defaultMavenJarDir = 'mvn_jar'; + + MavenDownloads({ + this.sourceDeps = const [], + // ASK: Should this be changed to a gitignore'd directory like build ? + this.sourceDir = defaultMavenSourceDir, + this.jarOnlyDeps = const [], + this.jarDir = defaultMavenJarDir, + }); + List sourceDeps; + String sourceDir; + List jarOnlyDeps; + String jarDir; +} + +/// Configuration for Android SDK sources and stub JAR files. +/// +/// The SDK directories for platform stub JARs and sources are searched in the +/// same order in which [versions] are specified. +/// +/// If [addGradleDeps] is true, a gradle stub is run in order to collect the +/// actual compile classpath of the `android/` subproject. +/// This will fail if there was no previous build of the project, or if a +/// `clean` task was run either through flutter or gradle wrapper. In such case, +/// it's required to run `flutter build apk` & retry running `jnigen`. +/// +/// A configuration is invalid if [versions] is unspecified or empty, and gradle +/// options are also false. If [sdkRoot] is not specified but versions is +/// specified, an attempt is made to find out SDK installation directory using +/// environment variable `ANDROID_SDK_ROOT` if it's defined, else an error +/// will be thrown. +class AndroidSdkConfig { + AndroidSdkConfig({ + this.versions, + this.sdkRoot, + this.addGradleDeps = false, + this.addGradleSources = false, + this.androidExample, + }) { + if (versions != null && sdkRoot == null) { + throw ConfigException("No SDK Root specified for finding Android SDK " + "from version priority list $versions"); + } + if (versions == null && !addGradleDeps && !addGradleSources) { + throw ConfigException('Neither any SDK versions nor `addGradleDeps` ' + 'is specified. Unable to find Android libraries.'); + } + } + + /// Versions of android SDK to search for, in decreasing order of preference. + List? versions; + + /// Root of Android SDK installation, this should be normally given on + /// command line or by setting `ANDROID_SDK_ROOT`, since this varies from + /// system to system. + String? sdkRoot; + + /// Attempt to determine exact compile time dependencies by running a gradle + /// stub in android subproject of this project. + /// + /// An Android build must have happened before we are able to obtain classpath + /// of Gradle dependencies. Run `flutter build apk` before running a jnigen + /// script with this option. + /// + /// For the same reason, if the flutter project is a plugin instead of + /// application, it's not possible to determine the build classpath directly. + /// Please provide [androidExample] pointing to an example application in + /// that case. + bool addGradleDeps; + + /// Similar to [addGradleDeps], runs a stub to obtain source dependencies of + /// the Android project. + /// + /// This may cause additional source JAR artifacts to be downloaded. Like the + /// [addGradleDeps] option, plugins cannot be built so an example should be + /// specified. + bool addGradleSources; + + /// Relative path to example application which will be used to determine + /// compile time classpath using a gradle stub. For most Android plugin + /// packages, 'example' will be the name of example application created inside + /// the package. This example should be built once before using this option, + /// so that gradle would have resolved all the dependencies. + String? androidExample; +} + +extension on String { + /// Converts the enum name from camelCase to snake_case. + String toSnakeCase() { + return splitMapJoin( + RegExp('[A-Z]'), + onMatch: (p) => '_${p[0]!.toLowerCase()}', + ); + } +} + +extension on Iterable { + Map valuesMap() { + return Map.fromEntries(map((e) => MapEntry(e.name.toSnakeCase(), e))); + } +} + +T _getEnumValueFromString( + Map values, String? name, T defaultVal) { + if (name == null) return defaultVal; + final value = values[name]; + if (value == null) { + throw ConfigException('Got: $name, allowed: ${values.keys}'); + } + return value; +} + +/// Additional options to pass to the summary generator component. +class SummarizerOptions { + SummarizerOptions( + {this.extraArgs = const [], this.workingDirectory, this.backend}); + List extraArgs; + Uri? workingDirectory; + SummarizerBackend? backend; +} + +/// Backend for reading summary of Java libraries +enum SummarizerBackend { + /// Generate Java API summaries using JARs in provided `classPath`s. + asm, + + /// Generate Java API summaries using source files in provided `sourcePath`s. + doclet, +} + +SummarizerBackend? getSummarizerBackend( + String? name, + SummarizerBackend? defaultVal, +) { + return _getEnumValueFromString( + SummarizerBackend.values.valuesMap(), + name, + defaultVal, + ); +} + +void _ensureIsDirectory(String name, Uri path) { + if (!path.toFilePath().endsWith(Platform.pathSeparator)) { + throw ConfigException('$name must be a directory path. If using YAML ' + 'config, please ensure the path ends with a slash (/).'); + } +} + +enum OutputStructure { packageStructure, singleFile } + +OutputStructure getOutputStructure(String? name, OutputStructure defaultVal) { + return _getEnumValueFromString( + OutputStructure.values.valuesMap(), + name, + defaultVal, + ); +} + +enum BindingsType { cBased, dartOnly } + +extension GetConfigString on BindingsType { + String getConfigString() { + return name.toSnakeCase(); + } +} + +BindingsType getBindingsType(String? name, BindingsType defaultVal) { + return _getEnumValueFromString( + BindingsType.values.valuesMap(), + name, + defaultVal, + ); +} + +class CCodeOutputConfig { + CCodeOutputConfig({ + required this.path, + required this.libraryName, + this.subdir, + }) { + _ensureIsDirectory('C output path', path); + if (subdir != null) { + _ensureIsDirectory('C subdirectory', path.resolve(subdir!)); + } + } + + /// Directory to write JNI C Bindings, in C+Dart mode. + /// + /// Strictly speaking, this is the root to place the `CMakeLists.txt` file + /// for the generated C bindings. It may be desirable to use the [subdir] + /// options to write C files to a subdirectory of [path]. For instance, + /// when generated code is required to be in `third_party` directory. + Uri path; + + /// Name of generated library in CMakeLists.txt configuration. + /// + /// This will also determine the name of shared object file. + String libraryName; + + /// Subfolder relative to [path] to write generated C code. + String? subdir; +} + +class DartCodeOutputConfig { + DartCodeOutputConfig({ + required this.path, + this.structure = OutputStructure.packageStructure, + }) { + if (structure == OutputStructure.singleFile) { + if (p.extension(path.toFilePath()) != '.dart') { + throw ConfigException( + 'Dart\'s output path must end with ".dart" in single file mode.'); + } + } else { + _ensureIsDirectory('Dart output path', path); + } + } + + /// Path to write generated Dart bindings. + Uri path; + + /// File structure of the generated Dart bindings. + OutputStructure structure; +} + +class SymbolsOutputConfig { + /// Path to write generated Dart bindings. + final Uri path; + + SymbolsOutputConfig(this.path) { + if (p.extension(path.toFilePath()) != '.yaml') { + throw ConfigException('Symbol\'s output path must end with ".yaml".'); + } + } +} + +class OutputConfig { + OutputConfig({ + required this.dartConfig, + this.bindingsType = BindingsType.cBased, + this.cConfig, + this.symbolsConfig, + }) { + if (bindingsType == BindingsType.cBased && cConfig == null) { + throw ConfigException('C output config must be provided!'); + } + } + BindingsType bindingsType; + DartCodeOutputConfig dartConfig; + CCodeOutputConfig? cConfig; + SymbolsOutputConfig? symbolsConfig; +} + +class BindingExclusions { + BindingExclusions({this.methods, this.fields, this.classes}); + MethodFilter? methods; + FieldFilter? fields; + ClassFilter? classes; +} + +bool _isCapitalized(String s) { + final firstLetter = s.substring(0, 1); + return firstLetter == firstLetter.toUpperCase(); +} + +void _validateClassName(String className) { + final parts = className.split('.'); + assert(parts.isNotEmpty); + const nestedClassesInfo = + "Nested classes cannot be specified separately. Specifying the " + "parent class will pull the nested classes."; + if (parts.length > 1 && _isCapitalized(parts[parts.length - 2])) { + // Try to detect possible nested classes specified using dot notation eg: + // `com.package.Class.NestedClass` and emit a warning. + log.warning("It appears a nested class $className is specified in the " + "config. $nestedClassesInfo"); + } + if (className.contains('\$')) { + throw ConfigException( + "Nested class $className not allowed. $nestedClassesInfo"); + } +} + +/// Configuration for jnigen binding generation. +class Config { + Config({ + required this.outputConfig, + required this.classes, + this.experiments, + this.exclude, + this.sourcePath, + this.classPath, + this.preamble, + this.customClassBody, + this.androidSdkConfig, + this.mavenDownloads, + this.summarizerOptions, + this.logLevel = Level.INFO, + this.dumpJsonTo, + this.imports, + }) { + for (final className in classes) { + _validateClassName(className); + } + } + + /// Output configuration for generated bindings + OutputConfig outputConfig; + + /// List of classes or packages for which bindings have to be generated. + /// + /// The names must be fully qualified, and it's assumed that the directory + /// structure corresponds to package naming. For example, com.abc.MyClass + /// should be resolvable as `com/abc/MyClass.java` from one of the provided + /// source paths. Same applies if ASM backend is used, except that the file + /// name suffix is `.class`. + List classes; + + Set? experiments; + + /// Methods and fields to be excluded from generated bindings. + final BindingExclusions? exclude; + + /// Paths to search for java source files. + /// + /// If a source package is downloaded through [mavenDownloads] option, + /// the corresponding source folder is automatically added and does not + /// need to be explicitly specified. + List? sourcePath; + + /// class path for scanning java libraries. If [backend] is `asm`, the + /// specified classpath is used to search for [classes], otherwise it's + /// merely used by the doclet API to find transitively referenced classes, + /// but not the specified classes / packages themselves. + List? classPath; + + /// Common text to be pasted on top of generated C and Dart files. + final String? preamble; + + /// Configuration to search for Android SDK libraries (Experimental). + final AndroidSdkConfig? androidSdkConfig; + + /// Configuration for auto-downloading JAR / source packages using maven, + /// along with their transitive dependencies. + final MavenDownloads? mavenDownloads; + + /// Additional options for the summarizer component. + SummarizerOptions? summarizerOptions; + + /// List of dependencies. + final List? imports; + + /// Call [importClasses] before using this. + late final Map importedClasses; + + /// Custom code that is added to the end of the class body with the specified + /// binary name. + /// + /// Used for testing package:jnigen. + final Map? customClassBody; + + Future importClasses() async { + importedClasses = {}; + for (final import in [ + // Implicitly importing package:jni symbols. + Uri.parse('package:jni/jni_symbols.yaml'), + ...?imports, + ]) { + // Getting the actual uri in case of package uris. + final Uri yamlUri; + final String importPath; + if (import.scheme == 'package') { + final packageName = import.pathSegments.first; + final packageRoot = await findPackageRoot(packageName); + if (packageRoot == null) { + log.fatal('package:$packageName was not found.'); + } + yamlUri = packageRoot + .resolve('lib/') + .resolve(import.pathSegments.sublist(1).join('/')); + importPath = 'package:$packageName'; + } else { + yamlUri = import; + importPath = ([...import.pathSegments]..removeLast()).join('/'); + } + log.finest('Parsing yaml file in url $yamlUri.'); + final YamlMap yaml; + try { + final symbolsFile = File.fromUri(yamlUri); + final content = symbolsFile.readAsStringSync(); + yaml = loadYaml(content, sourceUrl: yamlUri); + } on UnsupportedError catch (_) { + log.fatal('Could not reference "$import".'); + } catch (e, s) { + log.warning(e); + log.warning(s); + log.fatal('Error while parsing yaml file "$import".'); + } + final version = Version.parse(yaml['version'] as String); + if (!VersionConstraint.compatibleWith(_currentVersion).allows(version)) { + log.fatal('"$import" is version "$version" which is not compatible with' + 'the current JNIgen symbols version $_currentVersion'); + } + final files = yaml['files'] as YamlMap; + for (final entry in files.entries) { + final filePath = entry.key as String; + final classes = entry.value as YamlMap; + for (final classEntry in classes.entries) { + final binaryName = classEntry.key as String; + final decl = classEntry.value as YamlMap; + if (importedClasses.containsKey(binaryName)) { + log.fatal( + 'Re-importing "$binaryName" in "$import".\n' + 'Try hiding the class in import.', + ); + } + final classDecl = ClassDecl( + declKind: DeclKind.classKind, + binaryName: binaryName, + ) + ..path = '$importPath/$filePath' + ..finalName = decl['name'] + ..typeClassName = decl['type_class'] + ..superCount = decl['super_count'] + ..allTypeParams = [] + ..parent = null; + for (final typeParamEntry + in ((decl['type_params'] as YamlMap?)?.entries) ?? + >[]) { + final typeParamName = typeParamEntry.key as String; + final bounds = (typeParamEntry.value as YamlMap).entries.map((e) { + final boundName = e.key as String; + // Can only be DECLARED or TYPE_VARIABLE + if (!['DECLARED', 'TYPE_VARIABLE'].contains(e.value)) { + log.fatal( + 'Unsupported bound kind "${e.value}" for bound "$boundName" ' + 'in type parameter "$typeParamName" ' + 'of "$binaryName".', + ); + } + final boundKind = (e.value as String) == 'DECLARED' + ? Kind.declared + : Kind.typeVariable; + final ReferredType type; + if (boundKind == Kind.declared) { + type = DeclaredType(binaryName: boundName); + } else { + type = TypeVar(name: boundName); + } + return TypeUsage( + shorthand: binaryName, + kind: boundKind, + typeJson: {}, + )..type = type; + }).toList(); + classDecl.allTypeParams.add( + TypeParam(name: typeParamName, bounds: bounds), + ); + } + classDecl.methodNumsAfterRenaming = + (decl['methods'] as YamlMap?)?.cast() ?? {}; + importedClasses[binaryName] = classDecl; + } + } + } + } + + /// Directory containing the YAML configuration file, if any. + Uri? get configRoot => _configRoot; + Uri? _configRoot; + + /// Log verbosity. The possible values in decreasing order of verbosity + /// are verbose > debug > info > warning > error. Defaults to [LogLevel.info] + Level logLevel = Level.INFO; + + /// File to which JSON summary is written before binding generation. + final String? dumpJsonTo; + + static final _levels = Map.fromEntries( + Level.LEVELS.map((l) => MapEntry(l.name.toLowerCase(), l))); + + static Config parseArgs(List args) { + final prov = YamlReader.parseArgs(args); + + final List missingValues = []; + + T must(T? Function(String) f, T ifNull, String property) { + final res = f(property); + if (res == null) { + missingValues.add(property); + return ifNull; + } + return res; + } + + MemberFilter? regexFilter(String property) { + final exclusions = prov.getStringList(property); + if (exclusions == null) return null; + final List> filters = []; + for (var exclusion in exclusions) { + final split = exclusion.split('#'); + if (split.length != 2) { + throw ConfigException('Error parsing exclusion: "$exclusion": ' + 'expected to be in binaryName#member format.'); + } + filters.add(MemberNameFilter.exclude( + RegExp(split[0]), + RegExp(split[1]), + )); + } + return CombinedMemberFilter(filters); + } + + String? getSdkRoot() { + final root = prov.getString(_Props.androidSdkRoot) ?? + Platform.environment['ANDROID_SDK_ROOT']; + return root; + } + + Level logLevelFromString(String? levelName) { + if (levelName == null) return Level.INFO; + final level = _levels[levelName.toLowerCase()]; + if (level == null) { + throw ConfigException('Not a valid logging level: $levelName'); + } + return level; + } + + final configRoot = prov.getConfigRoot(); + String resolveFromConfigRoot(String reference) => + configRoot?.resolve(reference).toFilePath() ?? reference; + + final config = Config( + sourcePath: prov.getPathList(_Props.sourcePath), + classPath: prov.getPathList(_Props.classPath), + classes: must(prov.getStringList, [], _Props.classes), + summarizerOptions: SummarizerOptions( + extraArgs: prov.getStringList(_Props.summarizerArgs) ?? const [], + backend: getSummarizerBackend(prov.getString(_Props.backend), null), + workingDirectory: prov.getPath(_Props.summarizerWorkingDir), + ), + exclude: BindingExclusions( + methods: regexFilter(_Props.excludeMethods), + fields: regexFilter(_Props.excludeFields), + ), + outputConfig: OutputConfig( + bindingsType: getBindingsType( + prov.getString(_Props.bindingsType), + BindingsType.cBased, + ), + cConfig: prov.hasValue(_Props.cCodeOutputConfig) + ? CCodeOutputConfig( + libraryName: must(prov.getString, '', _Props.libraryName), + path: must(prov.getPath, Uri.parse('.'), _Props.cRoot), + subdir: prov.getString(_Props.cSubdir), + ) + : null, + dartConfig: DartCodeOutputConfig( + path: must(prov.getPath, Uri.parse('.'), _Props.dartRoot), + structure: getOutputStructure( + prov.getString(_Props.outputStructure), + OutputStructure.packageStructure, + ), + ), + symbolsConfig: prov.hasValue(_Props.symbolsOutputConfig) + ? SymbolsOutputConfig( + must(prov.getPath, Uri.parse('.'), _Props.symbolsOutputConfig), + ) + : null, + ), + preamble: prov.getString(_Props.preamble), + experiments: prov + .getStringList(_Props.experiments) + ?.map( + (e) => Experiment.fromString(e), + ) + .toSet(), + imports: prov.getPathList(_Props.import), + mavenDownloads: prov.hasValue(_Props.mavenDownloads) + ? MavenDownloads( + sourceDeps: prov.getStringList(_Props.sourceDeps) ?? const [], + sourceDir: prov.getPath(_Props.mavenSourceDir)?.toFilePath() ?? + resolveFromConfigRoot(MavenDownloads.defaultMavenSourceDir), + jarOnlyDeps: prov.getStringList(_Props.jarOnlyDeps) ?? const [], + jarDir: prov.getPath(_Props.mavenJarDir)?.toFilePath() ?? + resolveFromConfigRoot(MavenDownloads.defaultMavenJarDir), + ) + : null, + androidSdkConfig: prov.hasValue(_Props.androidSdkConfig) + ? AndroidSdkConfig( + versions: prov + .getStringList(_Props.androidSdkVersions) + ?.map(int.parse) + .toList(), + sdkRoot: getSdkRoot(), + addGradleDeps: prov.getBool(_Props.addGradleDeps) ?? false, + addGradleSources: prov.getBool(_Props.addGradleSources) ?? false, + // Leaving this as getString instead of getPath, because + // it's resolved later in android_sdk_tools. + androidExample: prov.getString(_Props.androidExample), + ) + : null, + logLevel: logLevelFromString( + prov.getOneOf( + _Props.logLevel, + _levels.keys.toSet(), + ), + ), + ); + if (missingValues.isNotEmpty) { + stderr.write('Following config values are required but not provided\n' + 'Please provide these properties through YAML ' + 'or use the command line switch -D=.\n'); + for (var missing in missingValues) { + stderr.writeln('* $missing'); + } + if (missingValues.contains(_Props.androidSdkRoot)) { + stderr.writeln('Please specify ${_Props.androidSdkRoot} through ' + 'command line or ensure that the ANDROID_SDK_ROOT environment ' + 'variable is set.'); + } + exit(1); + } + config._configRoot = configRoot; + return config; + } +} + +class _Props { + static const summarizer = 'summarizer'; + static const summarizerArgs = '$summarizer.extra_args'; + static const summarizerWorkingDir = '$summarizer.working_dir'; + static const backend = '$summarizer.backend'; + + static const sourcePath = 'source_path'; + static const classPath = 'class_path'; + static const classes = 'classes'; + static const exclude = 'exclude'; + static const excludeMethods = '$exclude.methods'; + static const excludeFields = '$exclude.fields'; + + static const experiments = 'enable_experiment'; + static const import = 'import'; + static const outputConfig = 'output'; + static const bindingsType = '$outputConfig.bindings_type'; + static const cCodeOutputConfig = '$outputConfig.c'; + static const dartCodeOutputConfig = '$outputConfig.dart'; + static const symbolsOutputConfig = '$outputConfig.symbols'; + static const cRoot = '$cCodeOutputConfig.path'; + static const cSubdir = '$cCodeOutputConfig.subdir'; + static const dartRoot = '$dartCodeOutputConfig.path'; + static const outputStructure = '$dartCodeOutputConfig.structure'; + static const libraryName = '$cCodeOutputConfig.library_name'; + static const preamble = 'preamble'; + static const logLevel = 'log_level'; + + static const mavenDownloads = 'maven_downloads'; + static const sourceDeps = '$mavenDownloads.source_deps'; + static const mavenSourceDir = '$mavenDownloads.source_dir'; + static const jarOnlyDeps = '$mavenDownloads.jar_only_deps'; + static const mavenJarDir = '$mavenDownloads.jar_dir'; + + static const androidSdkConfig = 'android_sdk_config'; + static const androidSdkRoot = '$androidSdkConfig.sdk_root'; + static const androidSdkVersions = '$androidSdkConfig.versions'; + static const addGradleDeps = '$androidSdkConfig.add_gradle_deps'; + static const addGradleSources = '$androidSdkConfig.add_gradle_sources'; + static const androidExample = '$androidSdkConfig.android_example'; +} diff --git a/pkgs/jnigen/lib/src/config/experiments.dart b/pkgs/jnigen/lib/src/config/experiments.dart new file mode 100644 index 000000000..6bb65c10f --- /dev/null +++ b/pkgs/jnigen/lib/src/config/experiments.dart @@ -0,0 +1,38 @@ +// Copyright (c) 2023, 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. + +class Experiment { + static const available = [ + interfaceImplementation, + ]; + + static const interfaceImplementation = Experiment( + name: 'interface_implementation', + description: 'Enables generation of machinery for ' + 'implementing Java interfaces in Dart.', + isExpired: false, + ); + + final String name; + final String description; + final bool isExpired; + + const Experiment({ + required this.name, + required this.description, + required this.isExpired, + }); + + factory Experiment.fromString(String s) { + final search = available.where((element) => element.name == s); + if (search.isEmpty) { + throw 'The experiment $s is not available in this version.'; + } + final result = search.single; + if (result.isExpired) { + throw 'The experiment $s can no longer be used in this version.'; + } + return result; + } +} diff --git a/pkgs/jnigen/lib/src/config/filters.dart b/pkgs/jnigen/lib/src/config/filters.dart new file mode 100644 index 000000000..1d0e1a5a4 --- /dev/null +++ b/pkgs/jnigen/lib/src/config/filters.dart @@ -0,0 +1,118 @@ +// 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. + +import '../elements/elements.dart'; + +bool _matchesCompletely(String string, Pattern pattern) { + final match = pattern.matchAsPrefix(string); + return match != null && match.group(0) == string; +} + +/// A filter which tells if bindings for given [ClassDecl] are generated. +abstract class ClassFilter { + bool included(ClassDecl decl); +} + +/// This filter includes the declarations for which [predicate] returns true. +class CustomClassFilter implements ClassFilter { + CustomClassFilter(this.predicate); + final bool Function(ClassDecl) predicate; + @override + bool included(ClassDecl decl) { + return predicate(decl); + } +} + +/// Filter to include / exclude classes by matching on the binary name. +/// A binary name is like qualified name but with a `$` used to indicate nested +/// class instead of `.`, guaranteeing a unique name. +class ClassNameFilter implements ClassFilter { + ClassNameFilter.include(this.pattern) : onMatch = true; + ClassNameFilter.exclude(this.pattern) : onMatch = false; + final bool onMatch; + final Pattern pattern; + @override + bool included(ClassDecl decl) { + if (_matchesCompletely(decl.binaryName, pattern)) { + return onMatch; + } + return !onMatch; + } +} + +abstract class MemberFilter { + bool included(ClassDecl classDecl, T member); +} + +/// Filter that excludes or includes members based on class and member name. +class MemberNameFilter implements MemberFilter { + MemberNameFilter.include(this.classPattern, this.namePattern) + : onMatch = true; + MemberNameFilter.exclude(this.classPattern, this.namePattern) + : onMatch = false; + final bool onMatch; + final Pattern classPattern, namePattern; + @override + bool included(ClassDecl classDecl, T member) { + final matches = _matchesCompletely(classDecl.binaryName, classPattern) && + _matchesCompletely(member.name, namePattern); + return matches ? onMatch : !onMatch; + } +} + +/// Filter that includes or excludes a member based on a custom callback. +class CustomMemberFilter implements MemberFilter { + CustomMemberFilter(this.predicate); + bool Function(ClassDecl, T) predicate; + @override + bool included(ClassDecl classDecl, T member) => predicate(classDecl, member); +} + +/// Filter which excludes classes excluded by any one filter in [filters]. +class CombinedClassFilter implements ClassFilter { + CombinedClassFilter.all(this.filters); + final List filters; + @override + bool included(ClassDecl decl) => filters.every((f) => f.included(decl)); +} + +/// Filter which excludes members excluded by any one filter in [filters]. +class CombinedMemberFilter implements MemberFilter { + CombinedMemberFilter(this.filters); + + final List> filters; + + @override + bool included(ClassDecl decl, T member) { + return filters.every((f) => f.included(decl, member)); + } +} + +typedef FieldFilter = MemberFilter; +typedef MethodFilter = MemberFilter; + +/// Filter using binary name of the class and name of the field. +typedef FieldNameFilter = MemberNameFilter; + +/// Filter using binary name of the class and name of the method. +typedef MethodNameFilter = MemberNameFilter; + +/// Predicate based filter for field, which can access class declaration +/// and the field. +typedef CustomFieldFilter = CustomMemberFilter; + +/// Predicate based filter for method, which can access class declaration +/// and the method. +typedef CustomMethodFilter = CustomMemberFilter; + +/// This filter excludes fields if any one of sub-filters returns false. +typedef CombinedFieldFilter = CombinedMemberFilter; + +/// This filter excludes methods if any one of sub-filters returns false. +typedef CombinedMethodFilter = CombinedMemberFilter; + +MemberFilter excludeAll(List> names) { + return CombinedMemberFilter( + names.map((p) => MemberNameFilter.exclude(p[0], p[1])).toList()); +} diff --git a/pkgs/jnigen/lib/src/config/yaml_reader.dart b/pkgs/jnigen/lib/src/config/yaml_reader.dart new file mode 100644 index 000000000..1cb1f46ca --- /dev/null +++ b/pkgs/jnigen/lib/src/config/yaml_reader.dart @@ -0,0 +1,115 @@ +// 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. + +import 'dart:io'; + +import 'package:args/args.dart'; +import 'package:yaml/yaml.dart'; +import 'package:cli_config/cli_config.dart' as cli_config; + +import 'config_exception.dart'; + +/// YAML Reader which enables to override specific values from command line. +class YamlReader { + final cli_config.Config _config; + + final Uri? _configRoot; + + YamlReader.of(this._config, this._configRoot); + + /// Parses the provided command line arguments and returns a [YamlReader]. + /// + /// This is a utility function which does all things a program would do when + /// parsing command line arguments, including exiting from the program when + /// arguments are invalid. + static YamlReader parseArgs(List args, + {bool allowYamlConfig = true}) { + final parser = ArgParser(); + parser.addFlag('help', abbr: 'h', help: 'Show this help.'); + + // Sometimes it's required to change a config value for a single invocation, + // then this option can be used. Conventionally in -D switch is used in + // C to set preprocessor variable & in java to override a config property. + + parser.addMultiOption('override', + abbr: 'D', + help: 'Override or assign a config property from command line.'); + if (allowYamlConfig) { + parser.addOption('config', abbr: 'c', help: 'Path to YAML config.'); + } + + final results = parser.parse(args); + if (results['help']) { + stderr.writeln(parser.usage); + exit(1); + } + final configFilePath = results['config'] as String?; + String? configFileContents; + Uri? configFileUri; + if (configFilePath != null) { + try { + configFileContents = File(configFilePath).readAsStringSync(); + configFileUri = File(configFilePath).uri; + } on Exception catch (e) { + stderr.writeln('Cannot read $configFilePath: $e.'); + } + } + final regex = RegExp('([a-z-_.]+)=(.+)'); + final properties = {}; + for (var prop in results['override']) { + final match = regex.matchAsPrefix(prop as String); + if (match != null && match.group(0) == prop) { + final propertyName = match.group(1); + final propertyValue = match.group(2); + properties[propertyName!] = propertyValue!; + } else { + throw ConfigException('override does not match expected pattern'); + } + } + final config = cli_config.Config.fromConfigFileContents( + commandLineDefines: results['override'], + workingDirectory: Directory.current.uri, + environment: Platform.environment, + fileContents: configFileContents, + fileSourceUri: configFileUri, + ); + return YamlReader.of( + config, + configFileUri?.resolve('.'), + ); + } + + bool? getBool(String property) => _config.optionalBool(property); + + String? getString(String property) => _config.optionalString(property); + + /// Same as [getString] but path is resolved relative to YAML config if it's + /// from YAML config. + Uri? getPath(String property) => _config.optionalPath(property); + + List? getStringList(String property) => _config.optionalStringList( + property, + splitCliPattern: ';', + combineAllConfigs: false, + ); + + List? getPathList(String property) => _config.optionalPathList( + property, + combineAllConfigs: false, + splitCliPattern: ';', + ); + + String? getOneOf(String property, Set values) => + _config.optionalString(property, validValues: values); + + Map? getStringMap(String property) { + final value = _config.valueOf(property); + return value?.cast(); + } + + bool hasValue(String property) => _config.valueOf(property) != null; + + /// Returns URI of the directory containing YAML config. + Uri? getConfigRoot() => _configRoot; +} diff --git a/pkgs/jnigen/lib/src/elements/elements.dart b/pkgs/jnigen/lib/src/elements/elements.dart new file mode 100644 index 000000000..020f05dbf --- /dev/null +++ b/pkgs/jnigen/lib/src/elements/elements.dart @@ -0,0 +1,681 @@ +// 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. + +import 'package:json_annotation/json_annotation.dart'; + +// Types to describe java API elements + +import '../bindings/visitor.dart'; + +part 'elements.g.dart'; + +abstract class Element> { + const Element(); + + R accept(Visitor v); +} + +@JsonEnum() + +/// A kind describes the type of a declaration. +enum DeclKind { + @JsonValue('CLASS') + classKind, + @JsonValue('INTERFACE') + interfaceKind, + @JsonValue('ENUM') + enumKind, +} + +class Classes implements Element { + const Classes(this.decls); + + final Map decls; + + factory Classes.fromJson(List json) { + final decls = {}; + for (final declJson in json) { + final classDecl = ClassDecl.fromJson(declJson); + decls[classDecl.binaryName] = classDecl; + } + return Classes(decls); + } + + @override + R accept(Visitor v) { + return v.visit(this); + } +} + +// Note: We give default values in constructor, if the field is nullable in +// JSON. this allows us to reduce JSON size by providing Include.NON_NULL +// option in java. + +@JsonSerializable(createToJson: false) +class ClassDecl extends ClassMember implements Element { + ClassDecl({ + this.annotations = const [], + this.javadoc, + required this.declKind, + this.modifiers = const {}, + required this.binaryName, + this.typeParams = const [], + this.methods = const [], + this.fields = const [], + this.superclass, + this.interfaces = const [], + this.hasStaticInit = false, + this.hasInstanceInit = false, + this.values, + this.kotlinClass, + }); + + @override + final Set modifiers; + + final List annotations; + final KotlinClass? kotlinClass; + final JavaDocComment? javadoc; + final DeclKind declKind; + final String binaryName; + List typeParams; + List methods; + List fields; + final List interfaces; + final bool hasStaticInit; + final bool hasInstanceInit; + + /// Will default to java.lang.Object if null by [Linker]. + TypeUsage? superclass; + + /// Contains enum constant names if class is an enum, + /// as obtained by `.values()` method in Java. + final List? values; + + String get internalName => binaryName.replaceAll(".", "/"); + + String get packageName => (binaryName.split('.')..removeLast()).join('.'); + + /// The number of super classes this type has. + /// + /// Populated by [Linker]. + @JsonKey(includeFromJson: false) + late final int superCount; + + /// Parent's [ClassDecl] obtained from [parentName]. + /// + /// Populated by [Linker]. + @JsonKey(includeFromJson: false) + late final ClassDecl? parent; + + /// Final name of this class. + /// + /// Populated by [Renamer]. + @JsonKey(includeFromJson: false) + late final String finalName; + + /// Name of the type class. + /// + /// Populated by [Renamer]. + @JsonKey(includeFromJson: false) + late final String typeClassName; + + /// Unique name obtained by renaming conflicting names with a number. + /// + /// This is used by C bindings instead of fully qualified name to reduce + /// the verbosity of generated bindings. + /// + /// Populated by [Renamer]. + @JsonKey(includeFromJson: false) + late final String uniqueName; + + /// Type parameters including the ones from its ancestors + /// + /// Populated by [Linker]. + @JsonKey(includeFromJson: false) + List allTypeParams = const []; + + /// The path which this class is generated in. + /// + /// Populated by [Linker]. + @JsonKey(includeFromJson: false) + late final String path; + + /// The numeric suffix of the methods. + /// + /// Populated by [Renamer]. + @JsonKey(includeFromJson: false) + late final Map methodNumsAfterRenaming; + + @override + String toString() { + return 'Java class declaration for $binaryName'; + } + + String get signature => 'L$internalName;'; + + factory ClassDecl.fromJson(Map json) => + _$ClassDeclFromJson(json); + + @override + R accept(Visitor v) { + return v.visit(this); + } + + @override + ClassDecl get classDecl => this; + + @override + String get name => finalName; + + bool get isObject => superCount == 0; + + @JsonKey(includeFromJson: false) + late final String? parentName = binaryName.contains(r'$') + ? binaryName.splitMapJoin(RegExp(r'\$[^$]+$'), onMatch: (_) => '') + : null; + + @JsonKey(includeFromJson: false) + late final isNested = parentName != null; +} + +@JsonEnum() +enum Kind { + @JsonValue('PRIMITIVE') + primitive, + @JsonValue('TYPE_VARIABLE') + typeVariable, + @JsonValue('WILDCARD') + wildcard, + @JsonValue('DECLARED') + declared, + @JsonValue('ARRAY') + array, +} + +@JsonSerializable(createToJson: false) +class TypeUsage { + TypeUsage({ + required this.shorthand, + required this.kind, + required this.typeJson, + }); + + static TypeUsage object = TypeUsage( + kind: Kind.declared, shorthand: 'java.lang.Object', typeJson: {}) + ..type = DeclaredType(binaryName: 'java.lang.Object'); + + final String shorthand; + final Kind kind; + + @JsonKey(name: "type") + final Map typeJson; + + /// Populated by [TypeUsage.fromJson]. + @JsonKey(includeFromJson: false) + late final ReferredType type; + + /// Populated by [Descriptor]. + @JsonKey(includeFromJson: false) + late String descriptor; + + String get name => type.name; + + // Since json_serializable doesn't directly support union types, + // we have to temporarily store `type` in a JSON map, and switch on the + // enum value received. + factory TypeUsage.fromJson(Map json) { + final t = _$TypeUsageFromJson(json); + switch (t.kind) { + case Kind.primitive: + t.type = PrimitiveType.fromJson(t.typeJson); + break; + case Kind.typeVariable: + t.type = TypeVar.fromJson(t.typeJson); + break; + case Kind.wildcard: + t.type = Wildcard.fromJson(t.typeJson); + break; + case Kind.declared: + t.type = DeclaredType.fromJson(t.typeJson); + break; + case Kind.array: + t.type = ArrayType.fromJson(t.typeJson); + break; + } + return t; + } + + R accept(TypeVisitor v) { + return type.accept(v); + } +} + +abstract class ReferredType { + const ReferredType(); + String get name; + + R accept(TypeVisitor v); +} + +class PrimitiveType extends ReferredType { + static const _primitives = { + 'byte': PrimitiveType._( + name: 'byte', + signature: 'B', + dartType: 'int', + boxedName: 'Byte', + cType: 'int8_t', + ffiType: 'Int8', + ), + 'short': PrimitiveType._( + name: 'short', + signature: 'S', + dartType: 'int', + boxedName: 'Short', + cType: 'int16_t', + ffiType: 'Int16', + ), + 'char': PrimitiveType._( + name: 'char', + signature: 'C', + dartType: 'int', + boxedName: 'Character', + cType: 'uint16_t', + ffiType: 'Uint16', + ), + 'int': PrimitiveType._( + name: 'int', + signature: 'I', + dartType: 'int', + boxedName: 'Integer', + cType: 'int32_t', + ffiType: 'Int32', + ), + 'long': PrimitiveType._( + name: 'long', + signature: 'J', + dartType: 'int', + boxedName: 'Long', + cType: 'int64_t', + ffiType: 'Int64', + ), + 'float': PrimitiveType._( + name: 'float', + signature: 'F', + dartType: 'double', + boxedName: 'Float', + cType: 'float', + ffiType: 'Float', + ), + 'double': PrimitiveType._( + name: 'double', + signature: 'D', + dartType: 'double', + boxedName: 'Double', + cType: 'double', + ffiType: 'Double', + ), + 'boolean': PrimitiveType._( + name: 'boolean', + signature: 'Z', + dartType: 'bool', + boxedName: 'Boolean', + cType: 'uint8_t', + ffiType: 'Uint8', + ), + 'void': PrimitiveType._( + name: 'void', + signature: 'V', + dartType: 'void', + boxedName: 'Void', // Not used. + cType: 'void', + ffiType: 'Void', + ), + }; + + const PrimitiveType._({ + required this.name, + required this.signature, + required this.dartType, + required this.boxedName, + required this.cType, + required this.ffiType, + }); + + @override + final String name; + + final String signature; + final String dartType; + final String boxedName; + final String cType; + final String ffiType; + + factory PrimitiveType.fromJson(Map json) { + return _primitives[json['name']]!; + } + + @override + R accept(TypeVisitor v) { + return v.visitPrimitiveType(this); + } +} + +@JsonSerializable(createToJson: false) +class DeclaredType extends ReferredType { + DeclaredType({ + required this.binaryName, + this.params = const [], + }); + + final String binaryName; + final List params; + + @JsonKey(includeFromJson: false) + late ClassDecl classDecl; + + @override + String get name => binaryName; + + factory DeclaredType.fromJson(Map json) => + _$DeclaredTypeFromJson(json); + + @override + R accept(TypeVisitor v) { + return v.visitDeclaredType(this); + } +} + +@JsonSerializable(createToJson: false) +class TypeVar extends ReferredType { + TypeVar({required this.name}); + + @override + String name; + + factory TypeVar.fromJson(Map json) => + _$TypeVarFromJson(json); + + @override + R accept(TypeVisitor v) { + return v.visitTypeVar(this); + } +} + +@JsonSerializable(createToJson: false) +class Wildcard extends ReferredType { + Wildcard({this.extendsBound, this.superBound}); + TypeUsage? extendsBound, superBound; + + @override + String get name => "?"; + + factory Wildcard.fromJson(Map json) => + _$WildcardFromJson(json); + + @override + R accept(TypeVisitor v) { + return v.visitWildcard(this); + } +} + +@JsonSerializable(createToJson: false) +class ArrayType extends ReferredType { + ArrayType({required this.type}); + TypeUsage type; + + @override + String get name => "[${type.name}"; + + factory ArrayType.fromJson(Map json) => + _$ArrayTypeFromJson(json); + + @override + R accept(TypeVisitor v) { + return v.visitArrayType(this); + } +} + +abstract class ClassMember { + String get name; + ClassDecl get classDecl; + Set get modifiers; + + bool get isStatic => modifiers.contains('static'); + bool get isFinal => modifiers.contains('final'); + bool get isPublic => modifiers.contains('public'); + bool get isProtected => modifiers.contains('protected'); +} + +@JsonSerializable(createToJson: false) +class Method extends ClassMember implements Element { + Method({ + this.annotations = const [], + this.javadoc, + this.modifiers = const {}, + required this.name, + this.descriptor, + this.typeParams = const [], + this.params = const [], + required this.returnType, + }); + + @override + final String name; + @override + final Set modifiers; + + final List annotations; + final JavaDocComment? javadoc; + final List typeParams; + List params; + final TypeUsage returnType; + + /// Can be used to match with [KotlinFunction]'s descriptor. + /// + /// Can create a unique signature in combination with [name]. + /// Populated either by the ASM backend or [Descriptor]. + String? descriptor; + + /// The [ClassDecl] where this method is defined. + /// + /// Populated by [Linker]. + @JsonKey(includeFromJson: false) + @override + late ClassDecl classDecl; + + /// Populated by [Renamer]. + @JsonKey(includeFromJson: false) + late String finalName; + + @JsonKey(includeFromJson: false) + late bool isOverridden; + + /// The actual return type when the method is a Kotlin's suspend fun. + /// + /// Populated by [KotlinProcessor]. + @JsonKey(includeFromJson: false) + TypeUsage? asyncReturnType; + + @JsonKey(includeFromJson: false) + late final String javaSig = '$name$descriptor'; + + bool get isCtor => name == ''; + + factory Method.fromJson(Map json) => _$MethodFromJson(json); + + @override + R accept(Visitor v) { + return v.visit(this); + } +} + +@JsonSerializable(createToJson: false) +class Param implements Element { + Param({ + this.annotations = const [], + this.javadoc, + required this.name, + required this.type, + }); + + final List annotations; + final JavaDocComment? javadoc; + final String name; + final TypeUsage type; + + /// Populated by [Renamer]. + @JsonKey(includeFromJson: false) + late String finalName; + + factory Param.fromJson(Map json) => _$ParamFromJson(json); + + @override + R accept(Visitor v) { + return v.visit(this); + } +} + +@JsonSerializable(createToJson: false) +class Field extends ClassMember implements Element { + Field({ + this.annotations = const [], + this.javadoc, + this.modifiers = const {}, + required this.name, + required this.type, + this.defaultValue, + }); + + @override + final String name; + @override + final Set modifiers; + + final List annotations; + final JavaDocComment? javadoc; + final TypeUsage type; + final Object? defaultValue; + + /// The [ClassDecl] where this field is defined. + /// + /// Populated by [Linker]. + @JsonKey(includeFromJson: false) + @override + late final ClassDecl classDecl; + + /// Populated by [Renamer]. + @JsonKey(includeFromJson: false) + late final String finalName; + + factory Field.fromJson(Map json) => _$FieldFromJson(json); + + @override + R accept(Visitor v) { + return v.visit(this); + } +} + +@JsonSerializable(createToJson: false) +class TypeParam implements Element { + TypeParam({required this.name, this.bounds = const []}); + + final String name; + final List bounds; + + @JsonKey(includeFromJson: false) + late final String erasure; + + factory TypeParam.fromJson(Map json) => + _$TypeParamFromJson(json); + + @override + R accept(Visitor v) { + return v.visit(this); + } +} + +@JsonSerializable(createToJson: false) +class JavaDocComment implements Element { + JavaDocComment({this.comment = ''}); + + final String comment; + + @JsonKey(includeFromJson: false) + late final String dartDoc; + + factory JavaDocComment.fromJson(Map json) => + _$JavaDocCommentFromJson(json); + + @override + R accept(Visitor v) { + return v.visit(this); + } +} + +@JsonSerializable(createToJson: false) +class Annotation implements Element { + Annotation({ + required this.binaryName, + this.properties = const {}, + }); + + final String binaryName; + final Map properties; + + factory Annotation.fromJson(Map json) => + _$AnnotationFromJson(json); + + @override + R accept(Visitor v) { + return v.visit(this); + } +} + +@JsonSerializable(createToJson: false) +class KotlinClass implements Element { + KotlinClass({ + required this.name, + this.functions = const [], + }); + + final String name; + final List functions; + + factory KotlinClass.fromJson(Map json) => + _$KotlinClassFromJson(json); + + @override + R accept(Visitor v) { + return v.visit(this); + } +} + +@JsonSerializable(createToJson: false) +class KotlinFunction implements Element { + KotlinFunction({ + required this.name, + required this.descriptor, + required this.kotlinName, + required this.isSuspend, + }); + + final String name; + + /// Used to match with [Method]'s descriptor. + /// + /// Creates a unique signature in combination with [name]. + final String descriptor; + final String kotlinName; + final bool isSuspend; + + factory KotlinFunction.fromJson(Map json) => + _$KotlinFunctionFromJson(json); + + @override + R accept(Visitor v) { + return v.visit(this); + } +} diff --git a/pkgs/jnigen/lib/src/elements/elements.g.dart b/pkgs/jnigen/lib/src/elements/elements.g.dart new file mode 100644 index 000000000..dcd35dd38 --- /dev/null +++ b/pkgs/jnigen/lib/src/elements/elements.g.dart @@ -0,0 +1,186 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'elements.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +ClassDecl _$ClassDeclFromJson(Map json) => ClassDecl( + annotations: (json['annotations'] as List?) + ?.map((e) => Annotation.fromJson(e as Map)) + .toList() ?? + const [], + javadoc: json['javadoc'] == null + ? null + : JavaDocComment.fromJson(json['javadoc'] as Map), + declKind: $enumDecode(_$DeclKindEnumMap, json['declKind']), + modifiers: (json['modifiers'] as List?) + ?.map((e) => e as String) + .toSet() ?? + const {}, + binaryName: json['binaryName'] as String, + typeParams: (json['typeParams'] as List?) + ?.map((e) => TypeParam.fromJson(e as Map)) + .toList() ?? + const [], + methods: (json['methods'] as List?) + ?.map((e) => Method.fromJson(e as Map)) + .toList() ?? + const [], + fields: (json['fields'] as List?) + ?.map((e) => Field.fromJson(e as Map)) + .toList() ?? + const [], + superclass: json['superclass'] == null + ? null + : TypeUsage.fromJson(json['superclass'] as Map), + interfaces: (json['interfaces'] as List?) + ?.map((e) => TypeUsage.fromJson(e as Map)) + .toList() ?? + const [], + hasStaticInit: json['hasStaticInit'] as bool? ?? false, + hasInstanceInit: json['hasInstanceInit'] as bool? ?? false, + values: + (json['values'] as List?)?.map((e) => e as String).toList(), + kotlinClass: json['kotlinClass'] == null + ? null + : KotlinClass.fromJson(json['kotlinClass'] as Map), + ); + +const _$DeclKindEnumMap = { + DeclKind.classKind: 'CLASS', + DeclKind.interfaceKind: 'INTERFACE', + DeclKind.enumKind: 'ENUM', +}; + +TypeUsage _$TypeUsageFromJson(Map json) => TypeUsage( + shorthand: json['shorthand'] as String, + kind: $enumDecode(_$KindEnumMap, json['kind']), + typeJson: json['type'] as Map, + ); + +const _$KindEnumMap = { + Kind.primitive: 'PRIMITIVE', + Kind.typeVariable: 'TYPE_VARIABLE', + Kind.wildcard: 'WILDCARD', + Kind.declared: 'DECLARED', + Kind.array: 'ARRAY', +}; + +DeclaredType _$DeclaredTypeFromJson(Map json) => DeclaredType( + binaryName: json['binaryName'] as String, + params: (json['params'] as List?) + ?.map((e) => TypeUsage.fromJson(e as Map)) + .toList() ?? + const [], + ); + +TypeVar _$TypeVarFromJson(Map json) => TypeVar( + name: json['name'] as String, + ); + +Wildcard _$WildcardFromJson(Map json) => Wildcard( + extendsBound: json['extendsBound'] == null + ? null + : TypeUsage.fromJson(json['extendsBound'] as Map), + superBound: json['superBound'] == null + ? null + : TypeUsage.fromJson(json['superBound'] as Map), + ); + +ArrayType _$ArrayTypeFromJson(Map json) => ArrayType( + type: TypeUsage.fromJson(json['type'] as Map), + ); + +Method _$MethodFromJson(Map json) => Method( + annotations: (json['annotations'] as List?) + ?.map((e) => Annotation.fromJson(e as Map)) + .toList() ?? + const [], + javadoc: json['javadoc'] == null + ? null + : JavaDocComment.fromJson(json['javadoc'] as Map), + modifiers: (json['modifiers'] as List?) + ?.map((e) => e as String) + .toSet() ?? + const {}, + name: json['name'] as String, + descriptor: json['descriptor'] as String?, + typeParams: (json['typeParams'] as List?) + ?.map((e) => TypeParam.fromJson(e as Map)) + .toList() ?? + const [], + params: (json['params'] as List?) + ?.map((e) => Param.fromJson(e as Map)) + .toList() ?? + const [], + returnType: + TypeUsage.fromJson(json['returnType'] as Map), + ); + +Param _$ParamFromJson(Map json) => Param( + annotations: (json['annotations'] as List?) + ?.map((e) => Annotation.fromJson(e as Map)) + .toList() ?? + const [], + javadoc: json['javadoc'] == null + ? null + : JavaDocComment.fromJson(json['javadoc'] as Map), + name: json['name'] as String, + type: TypeUsage.fromJson(json['type'] as Map), + ); + +Field _$FieldFromJson(Map json) => Field( + annotations: (json['annotations'] as List?) + ?.map((e) => Annotation.fromJson(e as Map)) + .toList() ?? + const [], + javadoc: json['javadoc'] == null + ? null + : JavaDocComment.fromJson(json['javadoc'] as Map), + modifiers: (json['modifiers'] as List?) + ?.map((e) => e as String) + .toSet() ?? + const {}, + name: json['name'] as String, + type: TypeUsage.fromJson(json['type'] as Map), + defaultValue: json['defaultValue'], + ); + +TypeParam _$TypeParamFromJson(Map json) => TypeParam( + name: json['name'] as String, + bounds: (json['bounds'] as List?) + ?.map((e) => TypeUsage.fromJson(e as Map)) + .toList() ?? + const [], + ); + +JavaDocComment _$JavaDocCommentFromJson(Map json) => + JavaDocComment( + comment: json['comment'] as String? ?? '', + ); + +Annotation _$AnnotationFromJson(Map json) => Annotation( + binaryName: json['binaryName'] as String, + properties: (json['properties'] as Map?)?.map( + (k, e) => MapEntry(k, e as Object), + ) ?? + const {}, + ); + +KotlinClass _$KotlinClassFromJson(Map json) => KotlinClass( + name: json['name'] as String, + functions: (json['functions'] as List?) + ?.map((e) => KotlinFunction.fromJson(e as Map)) + .toList() ?? + const [], + ); + +KotlinFunction _$KotlinFunctionFromJson(Map json) => + KotlinFunction( + name: json['name'] as String, + descriptor: json['descriptor'] as String, + kotlinName: json['kotlinName'] as String, + isSuspend: json['isSuspend'] as bool, + ); diff --git a/pkgs/jnigen/lib/src/generate_bindings.dart b/pkgs/jnigen/lib/src/generate_bindings.dart new file mode 100644 index 000000000..883ca8575 --- /dev/null +++ b/pkgs/jnigen/lib/src/generate_bindings.dart @@ -0,0 +1,59 @@ +// 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. + +import 'dart:io'; +import 'dart:convert'; + +import 'bindings/c_generator.dart'; +import 'bindings/dart_generator.dart'; +import 'bindings/descriptor.dart'; +import 'bindings/excluder.dart'; +import 'bindings/kotlin_processor.dart'; +import 'bindings/linker.dart'; +import 'bindings/unnester.dart'; +import 'bindings/renamer.dart'; +import 'elements/elements.dart'; +import 'summary/summary.dart'; +import 'config/config.dart'; +import 'tools/tools.dart'; +import 'logging/logging.dart'; + +void collectOutputStream(Stream> stream, StringBuffer buffer) => + stream.transform(const Utf8Decoder()).forEach(buffer.write); +Future generateJniBindings(Config config) async { + setLoggingLevel(config.logLevel); + + await buildSummarizerIfNotExists(); + + final Classes classes; + + try { + classes = await getSummary(config); + } on SummaryParseException catch (e) { + if (e.stderr != null) { + printError(e.stderr); + } + log.fatal(e.message); + } + + classes.accept(Excluder(config)); + classes.accept(KotlinProcessor()); + await classes.accept(Linker(config)); + classes.accept(const Unnester()); + classes.accept(const Descriptor()); + classes.accept(Renamer(config)); + + final cBased = config.outputConfig.bindingsType == BindingsType.cBased; + if (cBased) { + await classes.accept(CGenerator(config)); + } + + try { + await classes.accept(DartGenerator(config)); + log.info('Completed'); + } on Exception catch (e, trace) { + stderr.writeln(trace); + log.fatal('Error while writing bindings: $e'); + } +} diff --git a/pkgs/jnigen/lib/src/logging/logging.dart b/pkgs/jnigen/lib/src/logging/logging.dart new file mode 100644 index 000000000..71db21791 --- /dev/null +++ b/pkgs/jnigen/lib/src/logging/logging.dart @@ -0,0 +1,126 @@ +// 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. + +// coverage:ignore-file + +import 'dart:io'; +import 'package:logging/logging.dart'; + +const _ansiRed = '\x1b[31m'; +const _ansiYellow = '\x1b[33m'; +const _ansiDefault = '\x1b[39;49m'; + +String _colorize(String message, String colorCode) { + if (stderr.supportsAnsiEscapes) { + return '$colorCode$message$_ansiDefault'; + } + return message; +} + +/// Format [DateTime] for use in filename +String _formatTime(DateTime now) { + return '${now.year}-${now.month}-${now.day}-' + '${now.hour}.${now.minute}.${now.second}'; +} + +// We need to respect logging level for console but log everything to file. +// Hierarchical logging is convoluted. I'm just keeping track of log level. +var _logLevel = Level.INFO; + +final _logDirUri = Directory.current.uri.resolve(".dart_tool/jnigen/logs/"); + +final _logDir = () { + final dir = Directory.fromUri(_logDirUri); + dir.createSync(recursive: true); + return dir; +}(); + +Uri _getDefaultLogFileUri() => + _logDir.uri.resolve("jnigen-${_formatTime(DateTime.now())}.log"); + +IOSink? _logStream; + +/// Enable saving the logs to a file. +/// +/// This is only meant to be called from an application entry point such as +/// `main`. +void enableLoggingToFile() { + _deleteOldLogFiles(); + if (_logStream != null) { + throw StateError('Log file is already set'); + } + _logStream = File.fromUri(_getDefaultLogFileUri()).openWrite(); +} + +// Maximum number of log files to keep. +const _maxLogFiles = 5; + +/// Delete log files except most recent [_maxLogFiles] files. +void _deleteOldLogFiles() { + final logFiles = _logDir.listSync().map((f) => File(f.path)).toList(); + // sort in descending order of last modified time. + logFiles + .sort((f1, f2) => f2.lastModifiedSync().compareTo(f1.lastModifiedSync())); + final toDelete = logFiles.length < _maxLogFiles + ? const [] + : logFiles.sublist(_maxLogFiles - 1); + for (final oldLogFile in toDelete) { + oldLogFile.deleteSync(); + } +} + +Logger log = () { + // initialize the logger. + final jnigenLogger = Logger('jnigen'); + Logger.root.level = Level.ALL; + Logger.root.onRecord.listen((r) { + // Write to file regardless of level. + _logStream?.writeln('${r.level} ${r.time}: ${r.message}'); + // write to console only if level is above configured level. + if (r.level < _logLevel) { + return; + } + var message = '(${r.loggerName}) ${r.level.name}: ${r.message}'; + if ((r.level == Level.SHOUT || r.level == Level.SEVERE)) { + message = _colorize(message, _ansiRed); + } else if (r.level == Level.WARNING) { + message = _colorize(message, _ansiYellow); + } + stderr.writeln(message); + }); + return jnigenLogger; +}(); + +/// Set logging level to [level]. +void setLoggingLevel(Level level) { + log.fine('Set log level: $level'); + _logLevel = level; +} + +/// Prints [message] without logging information. +/// +/// Primarily used in printing output of failed commands. +void printError(Object? message) { + stderr.writeln(_colorize(message.toString(), _ansiRed)); +} + +extension FatalErrors on Logger { + Never fatal(Object? message, {int exitCode = 1}) { + message = _colorize('Fatal: $message', _ansiRed); + stderr.writeln(message); + return exit(exitCode); + } +} + +extension WriteToFile on Logger { + void writeToFile(Object? data) { + _logStream?.writeln(data); + } + + void writeSectionToFile(String? sectionName, Object? data) { + _logStream?.writeln("==== Begin $sectionName ===="); + _logStream?.writeln(data); + _logStream?.writeln("==== End $sectionName ===="); + } +} diff --git a/pkgs/jnigen/lib/src/summary/summary.dart b/pkgs/jnigen/lib/src/summary/summary.dart new file mode 100644 index 000000000..170627582 --- /dev/null +++ b/pkgs/jnigen/lib/src/summary/summary.dart @@ -0,0 +1,195 @@ +// 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. + +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; + +import '../../tools.dart'; +import '../config/config.dart'; +import '../elements/elements.dart'; +import '../generate_bindings.dart'; +import '../logging/logging.dart'; + +class SummaryParseException implements Exception { + final String? stderr; + final String message; + SummaryParseException(this.message) : stderr = null; + SummaryParseException.withStderr(this.stderr, this.message); + + @override + String toString() => message; +} + +/// A command based summary source which calls the ApiSummarizer command. +/// [sourcePaths] and [classPaths] can be provided for the summarizer to find +/// required dependencies. The [classes] argument specifies the fully qualified +/// names of classes or packages included in the generated summary. when a +/// package is specified, its contents are included recursively. +/// +/// When the default summarizer scans the [sourcePaths], it assumes that +/// the directory names reflect actual package paths. For example, a class name +/// com.example.pkg.Cls will be mapped to com/example/pkg/Cls.java. +/// +/// The default summarizer needs to be built with `jnigen:setup` +/// script before this API is used. +class SummarizerCommand { + SummarizerCommand({ + this.command = "java -jar .dart_tool/jnigen/ApiSummarizer.jar", + List? sourcePath, + List? classPath, + this.extraArgs = const [], + required this.classes, + this.workingDirectory, + this.backend, + }) : sourcePaths = sourcePath ?? [], + classPaths = classPath ?? []; + + static const sourcePathsOption = '-s'; + static const classPathsOption = '-c'; + + String command; + List sourcePaths, classPaths; + + List extraArgs; + List classes; + + Uri? workingDirectory; + SummarizerBackend? backend; + + void addSourcePaths(List paths) { + sourcePaths.addAll(paths); + } + + void addClassPaths(List paths) { + classPaths.addAll(paths); + } + + void _addPathParam(List args, String option, List paths) { + if (paths.isNotEmpty) { + final joined = paths + .map((uri) => uri.toFilePath()) + .join(Platform.isWindows ? ';' : ':'); + if (option.endsWith("=")) { + args.add(option + joined); + } else { + args.addAll([option, joined]); + } + } + } + + Future runProcess() async { + final commandSplit = command.split(" "); + final exec = commandSplit[0]; + final List args = commandSplit.sublist(1); + + _addPathParam(args, sourcePathsOption, sourcePaths); + _addPathParam(args, classPathsOption, classPaths); + if (backend != null) { + args.addAll(['--backend', backend!.name]); + } + args.addAll(extraArgs); + args.addAll(classes); + log.info('execute $exec ${args.join(' ')}'); + final proc = await Process.start(exec, args, + workingDirectory: workingDirectory?.toFilePath() ?? '.'); + return proc; + } +} + +Future getSummary(Config config) async { + // This function is a potential entry point in tests, which set log level to + // warning. + setLoggingLevel(config.logLevel); + final summarizer = SummarizerCommand( + sourcePath: config.sourcePath, + classPath: config.classPath, + classes: config.classes, + workingDirectory: config.summarizerOptions?.workingDirectory, + extraArgs: config.summarizerOptions?.extraArgs ?? const [], + backend: config.summarizerOptions?.backend, + ); + + // Additional sources added using maven downloads and gradle trickery. + final extraSources = []; + final extraJars = []; + final mavenDl = config.mavenDownloads; + if (mavenDl != null) { + final sourcePath = mavenDl.sourceDir; + await Directory(sourcePath).create(recursive: true); + await MavenTools.downloadMavenSources( + MavenTools.deps(mavenDl.sourceDeps), sourcePath); + extraSources.add(Uri.directory(sourcePath)); + final jarPath = mavenDl.jarDir; + await Directory(jarPath).create(recursive: true); + await MavenTools.downloadMavenJars( + MavenTools.deps(mavenDl.sourceDeps + mavenDl.jarOnlyDeps), jarPath); + extraJars.addAll(await Directory(jarPath) + .list() + .where((entry) => entry.path.endsWith('.jar')) + .map((entry) => entry.uri) + .toList()); + } + final androidConfig = config.androidSdkConfig; + if (androidConfig != null && androidConfig.addGradleDeps) { + final deps = AndroidSdkTools.getGradleClasspaths( + configRoot: config.configRoot, + androidProject: androidConfig.androidExample ?? '.', + ); + extraJars.addAll(deps.map(Uri.file)); + } + if (androidConfig != null && androidConfig.addGradleSources) { + final deps = AndroidSdkTools.getGradleSources( + configRoot: config.configRoot, + androidProject: androidConfig.androidExample ?? '.', + ); + extraSources.addAll(deps.map(Uri.file)); + } + if (androidConfig != null && androidConfig.versions != null) { + final versions = androidConfig.versions!; + final androidSdkRoot = + androidConfig.sdkRoot ?? AndroidSdkTools.getAndroidSdkRoot(); + final androidJar = await AndroidSdkTools.getAndroidJarPath( + sdkRoot: androidSdkRoot, versionOrder: versions); + if (androidJar != null) { + extraJars.add(Uri.directory(androidJar)); + } + } + + summarizer.addSourcePaths(extraSources); + summarizer.addClassPaths(extraJars); + + Process process; + Stream> input; + final stopwatch = Stopwatch()..start(); + try { + process = await summarizer.runProcess(); + input = process.stdout; + } on Exception catch (e) { + throw SummaryParseException('Cannot generate API summary: $e'); + } + final stderrBuffer = StringBuffer(); + collectOutputStream(process.stderr, stderrBuffer); + final stream = const JsonDecoder().bind(const Utf8Decoder().bind(input)); + dynamic json; + try { + json = await stream.single; + stopwatch.stop(); + log.info('Parsing inputs took ${stopwatch.elapsedMilliseconds} ms'); + } on Exception catch (e) { + await process.exitCode; + throw SummaryParseException.withStderr( + stderrBuffer.toString(), + 'Cannot generate summary: $e', + ); + } finally { + log.writeSectionToFile("summarizer logs", stderrBuffer.toString()); + } + if (json == null) { + throw SummaryParseException('Expected JSON element from summarizer.'); + } + final list = json as List; + final classes = Classes.fromJson(list); + return classes; +} diff --git a/pkgs/jnigen/lib/src/tools/android_sdk_tools.dart b/pkgs/jnigen/lib/src/tools/android_sdk_tools.dart new file mode 100644 index 000000000..3de5575f0 --- /dev/null +++ b/pkgs/jnigen/lib/src/tools/android_sdk_tools.dart @@ -0,0 +1,226 @@ +// 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. + +import 'dart:io'; + +import 'package:path/path.dart'; + +import '../logging/logging.dart'; + +class _AndroidToolsException implements Exception { + _AndroidToolsException(this.message); + String message; + @override + String toString() => message; +} + +class SdkNotFoundException extends _AndroidToolsException { + SdkNotFoundException(String message) : super(message); +} + +class GradleException extends _AndroidToolsException { + GradleException(String message) : super(message); +} + +class AndroidSdkTools { + static String getAndroidSdkRoot() { + final envVar = Platform.environment['ANDROID_SDK_ROOT']; + if (envVar == null) { + throw SdkNotFoundException('Android SDK not found. Please set ' + 'ANDROID_SDK_ROOT environment variable or specify through command ' + 'line override.'); + } + return envVar; + } + + static Future _getVersionDir( + String relative, String sdkRoot, List versionOrder) async { + final parent = join(sdkRoot, relative); + for (var version in versionOrder) { + final dir = Directory(join(parent, 'android-$version')); + if (await dir.exists()) { + return dir.path; + } + } + return null; + } + + static Future _getFile(String sdkRoot, String relative, + List versionOrder, String file) async { + final platform = await _getVersionDir(relative, sdkRoot, versionOrder); + if (platform == null) return null; + final filePath = join(platform, file); + if (await File(filePath).exists()) { + log.info('Found $filePath'); + return filePath; + } + return null; + } + + static const _gradleCannotFindJars = 'Gradle stub cannot find JAR libraries. ' + 'This might be because no APK build has happened yet.'; + + static const _leftOverStubWarning = 'If you are seeing this error in ' + '`flutter build` output, it is likely that `jnigen` left some stubs in ' + 'the build.gradle file. Please restore that file from your version ' + 'control system or manually remove the stub functions named ' + '$_gradleGetClasspathTaskName and / or $_gradleGetSourcesTaskName.'; + + static Future getAndroidJarPath( + {required String sdkRoot, required List versionOrder}) async => + await _getFile(sdkRoot, 'platforms', versionOrder, 'android.jar'); + + static const _gradleGetClasspathTaskName = 'getReleaseCompileClasspath'; + + static const _gradleGetClasspathStub = ''' +// Gradle stub for listing dependencies in jnigen. If found in +// android/build.gradle, please delete the following function. +task $_gradleGetClasspathTaskName(type: Copy) { + project.afterEvaluate { + try { + def app = project(':app') + def android = app.android + def cp = [android.getBootClasspath()[0]] + android.applicationVariants.each { variant -> + if (variant.name.equals('release')) { + cp += variant.javaCompile.classpath.getFiles() + } + } + cp.each { println it } + } catch (Exception e) { + System.err.println("$_gradleCannotFindJars") + System.err.println("$_leftOverStubWarning") + throw e + } + } +} +'''; + + static const _gradleGetSourcesTaskName = 'getSources'; + // adapted from https://stackoverflow.com/questions/39975780/how-can-i-use-gradle-to-download-dependencies-and-their-source-files-and-place-t/39981143#39981143 + // Although it appears we can use this same code for getting JAR artifacts, + // there is no JAR equivalent for `org.gradle.language.base.Artifact`. + // So it appears different methods should be used for JAR artifacts. + static const _gradleGetSourcesStub = ''' +// Gradle stub for fetching source dependencies in jnigen. If found in +// android/build.gradle, please delete the following function. +task $_gradleGetSourcesTaskName(type: Copy) { + project.afterEvaluate { + def componentIds = project(':app').configurations.releaseCompileClasspath.incoming + .resolutionResult.allDependencies.collect { it.selected.id } + + ArtifactResolutionResult result = dependencies.createArtifactResolutionQuery() + .forComponents(componentIds) + .withArtifacts(JvmLibrary, SourcesArtifact) + .execute() + + def sourceArtifacts = [] + + result.resolvedComponents.each { ComponentArtifactsResult component -> + Set sources = component.getArtifacts(SourcesArtifact) + sources.each { ArtifactResult ar -> + if (ar instanceof ResolvedArtifactResult) { + sourceArtifacts << ar.file + } + } + } + sourceArtifacts.forEach { println it } + } + System.err.println("$_leftOverStubWarning") +} +'''; + + /// Get release compile classpath used by Gradle for android build. + /// + /// This function temporarily overwrites the build.gradle file by a stub with + /// function to list all dependency paths for release variant. + /// This function fails if no gradle build is attempted before. + /// + /// If current project is not directly buildable by gradle, eg: a plugin, + /// a relative path to other project can be specified using [androidProject]. + static List getGradleClasspaths( + {Uri? configRoot, String androidProject = '.'}) => + _runGradleStub( + stubName: _gradleGetClasspathTaskName, + stubCode: _gradleGetClasspathStub, + androidProject: androidProject, + configRoot: configRoot, + ); + + /// Get source paths for all gradle dependencies. + /// + /// This function temporarily overwrites the build.gradle file by a stub with + /// function to list all dependency paths for release variant. + /// This function fails if no gradle build is attempted before. + static List getGradleSources( + {Uri? configRoot, String androidProject = '.'}) { + return _runGradleStub( + stubName: _gradleGetSourcesTaskName, + stubCode: _gradleGetSourcesStub, + androidProject: androidProject, + configRoot: configRoot, + ); + } + + static String _appendStub(String script, String stub) { + return script.contains(stub) ? script : script + stub; + } + + static List _runGradleStub({ + required String stubName, + required String stubCode, + Uri? configRoot, + String androidProject = '.', + }) { + log.info('trying to obtain gradle dependencies [$stubName]...'); + if (configRoot != null) { + androidProject = configRoot.resolve(androidProject).toFilePath(); + } + final android = join(androidProject, 'android'); + final buildGradle = join(android, 'build.gradle'); + final buildGradleOld = join(android, 'build.gradle.old'); + final origBuild = File(buildGradle); + final script = origBuild.readAsStringSync(); + origBuild.renameSync(buildGradleOld); + origBuild.createSync(); + log.finer('Writing temporary gradle script with stub "$stubName"...'); + origBuild.writeAsStringSync(_appendStub(script, stubCode)); + log.finer('Running gradle wrapper...'); + final gradleCommand = Platform.isWindows ? '.\\gradlew.bat' : './gradlew'; + ProcessResult procRes; + try { + procRes = Process.runSync(gradleCommand, ['-q', stubName], + workingDirectory: android, runInShell: true); + } finally { + log.info('Restoring build scripts'); + origBuild.writeAsStringSync( + script + .replaceAll(_gradleGetClasspathStub, "") + .replaceAll(_gradleGetSourcesStub, ""), + ); + File(buildGradleOld).deleteSync(); + } + if (procRes.exitCode != 0) { + final inAndroidProject = + (androidProject == '.') ? '' : ' in $androidProject'; + throw GradleException('\n\ngradle exited with status ' + '${procRes.exitCode}\n. This can be because the Android build is not ' + 'yet cached. Please run `flutter build apk`$inAndroidProject and try ' + 'again\n'); + } + // Record both stdout and stderr of gradle. + log.writeSectionToFile("Gradle logs ($stubName)", procRes.stderr); + log.writeSectionToFile("Gradle output ($stubName)", procRes.stdout); + final output = procRes.stdout as String; + if (output.isEmpty) { + printError(procRes.stderr); + throw Exception("Gradle stub exited without output."); + } + final paths = (procRes.stdout as String) + .trim() + .split(Platform.isWindows ? '\r\n' : '\n'); + log.fine('Found ${paths.length} entries'); + return paths; + } +} diff --git a/pkgs/jnigen/lib/src/tools/build_summarizer.dart b/pkgs/jnigen/lib/src/tools/build_summarizer.dart new file mode 100644 index 000000000..1e0ec06a7 --- /dev/null +++ b/pkgs/jnigen/lib/src/tools/build_summarizer.dart @@ -0,0 +1,78 @@ +// 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. + +// TODO(#43): Address concurrently building summarizer. +// +// In the current state summarizer has to be built before tests, which run +// concurrently. Ignoring coverage for this file until that issue is addressed. +// +// coverage:ignore-file + +import 'dart:io'; + +import 'package:path/path.dart'; + +import '../logging/logging.dart'; +import '../util/find_package.dart'; + +final toolPath = join('.', '.dart_tool', 'jnigen'); +final mvnTargetDir = join(toolPath, 'target'); +final jarFile = join(toolPath, 'ApiSummarizer.jar'); +final targetJarFile = join(mvnTargetDir, 'ApiSummarizer.jar'); + +Future buildApiSummarizer() async { + final pkg = await findPackageRoot('jnigen'); + if (pkg == null) { + log.fatal('package jnigen not found!'); + } + final pom = pkg.resolve('java/pom.xml'); + await Directory(toolPath).create(recursive: true); + final mvnArgs = [ + 'compile', + '--batch-mode', + '--update-snapshots', + '-f', + pom.toFilePath(), + ]; + log.info('execute mvn ${mvnArgs.join(" ")}'); + try { + final mvnProc = await Process.run('mvn', mvnArgs, + workingDirectory: toolPath, runInShell: true); + final exitCode = mvnProc.exitCode; + if (exitCode == 0) { + await File(targetJarFile).rename(jarFile); + } else { + printError(mvnProc.stdout); + printError(mvnProc.stderr); + printError("maven exited with $exitCode"); + } + } finally { + await Directory(mvnTargetDir).delete(recursive: true); + } +} + +Future buildSummarizerIfNotExists({bool force = false}) async { + // TODO(#43): This function cannot be invoked concurrently because 2 processes + // will start building summarizer at once. Introduce a locking mechnanism so + // that when one process is building summarizer JAR, other process waits using + // exponential backoff. + final jarExists = await File(jarFile).exists(); + final isJarStale = jarExists && + await isPackageModifiedAfter( + 'jnigen', await File(jarFile).lastModified(), 'java/'); + if (isJarStale) { + log.info('Rebuilding ApiSummarizer component since sources ' + 'have changed. This might take some time.'); + } + if (!jarExists) { + log.info('Building ApiSummarizer component. ' + 'This might take some time. ' + 'The build will be cached for subsequent runs.'); + } + if (!jarExists || isJarStale || force) { + await buildApiSummarizer(); + } else { + log.info('ApiSummarizer.jar exists. Skipping build..'); + } +} diff --git a/pkgs/jnigen/lib/src/tools/maven_tools.dart b/pkgs/jnigen/lib/src/tools/maven_tools.dart new file mode 100644 index 000000000..74cb3a179 --- /dev/null +++ b/pkgs/jnigen/lib/src/tools/maven_tools.dart @@ -0,0 +1,142 @@ +// 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. + +import 'dart:io'; + +import 'package:path/path.dart'; + +import '../logging/logging.dart'; + +/// This class provides some utility methods to download a sources / jars +/// using maven along with transitive dependencies. +class MavenTools { + static final currentDir = Directory("."); + + /// Helper method since we can't pass inheritStdio option to [Process.run]. + static Future _runCmd(String exec, List args, + [String? workingDirectory]) async { + log.info('execute $exec ${args.join(" ")}'); + final proc = await Process.start(exec, args, + workingDirectory: workingDirectory, + runInShell: true, + mode: ProcessStartMode.inheritStdio); + return proc.exitCode; + } + + static Future _runMavenCommand( + List deps, + List mvnArgs, + Directory tempDir, + ) async { + final pom = _getStubPom(deps); + final tempPom = join(tempDir.path, "temp_pom.xml"); + final tempTarget = join(tempDir.path, "target"); + log.finer('using POM stub:\n$pom'); + await File(tempPom).writeAsString(pom); + await Directory(tempTarget).create(); + await _runCmd('mvn', ['-q', '-f', tempPom, ...mvnArgs]); + await File(tempPom).delete(); + await Directory(tempTarget).delete(recursive: true); + } + + /// Create a list of [MavenDependency] objects from maven coordinates in string form. + static List deps(List depNames) => + depNames.map(MavenDependency.fromString).toList(); + + /// Downloads and unpacks source files of [deps] into [targetDir]. + static Future downloadMavenSources( + List deps, String targetDir) async { + final tempDir = await currentDir.createTemp("maven_temp_"); + await _runMavenCommand( + deps, + [ + 'dependency:unpack-dependencies', + '-DexcludeTransitive=true', + '-DoutputDirectory=../$targetDir', + '-Dclassifier=sources', + ], + tempDir, + ); + await tempDir.delete(recursive: true); + } + + /// Downloads JAR files of all [deps] transitively into [targetDir]. + static Future downloadMavenJars( + List deps, String targetDir) async { + final tempDir = await currentDir.createTemp("maven_temp_"); + await _runMavenCommand( + deps, + [ + 'dependency:copy-dependencies', + '-DoutputDirectory=../$targetDir', + ], + tempDir, + ); + await tempDir.delete(recursive: true); + } + + static String _getStubPom(List deps, + {String javaVersion = '11'}) { + final depDecls = []; + for (var dep in deps) { + final otherTags = StringBuffer(); + for (var entry in dep.otherTags.entries) { + otherTags.write(''' + <${entry.key}> + ${entry.value} + + '''); + } + depDecls.add(''' + + ${dep.groupID} + ${dep.artifactID} + ${dep.version} + ${otherTags.toString()} + '''); + } + return ''' + + + + google-maven-repo + Google Maven Repository + https://maven.google.com + + + 4.0.0 + com.mycompany.app + jnigen_maven_stub + 1.0-SNAPSHOT + + $javaVersion + $javaVersion + + +${depDecls.join("\n")} + + + \${project.basedir}/target + +'''; + } +} + +/// Maven dependency with group ID, artifact ID, and version. +class MavenDependency { + MavenDependency(this.groupID, this.artifactID, this.version, + {this.otherTags = const {}}); + factory MavenDependency.fromString(String fullName) { + final components = fullName.split(':'); + if (components.length != 3) { + throw ArgumentError('invalid name for maven dependency: $fullName'); + } + return MavenDependency(components[0], components[1], components[2]); + } + String groupID, artifactID, version; + Map otherTags; +} diff --git a/pkgs/jnigen/lib/src/tools/tools.dart b/pkgs/jnigen/lib/src/tools/tools.dart new file mode 100644 index 000000000..9677a3e48 --- /dev/null +++ b/pkgs/jnigen/lib/src/tools/tools.dart @@ -0,0 +1,7 @@ +// 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. + +export 'android_sdk_tools.dart'; +export 'maven_tools.dart'; +export 'build_summarizer.dart'; diff --git a/pkgs/jnigen/lib/src/util/find_package.dart b/pkgs/jnigen/lib/src/util/find_package.dart new file mode 100644 index 000000000..89d95ddc0 --- /dev/null +++ b/pkgs/jnigen/lib/src/util/find_package.dart @@ -0,0 +1,46 @@ +// 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. + +import 'dart:io'; + +import 'package:package_config/package_config.dart'; + +Future findPackage(String packageName) async { + final packageConfig = await findPackageConfig(Directory.current); + if (packageConfig == null) { + return null; + } + return packageConfig[packageName]; +} + +Future findPackageRoot(String packageName) async { + return (await findPackage(packageName))?.root; +} + +Future isPackageModifiedAfter(String packageName, DateTime time, + [String? subDir]) async { + final root = await findPackageRoot(packageName); + if (root == null) { + throw UnsupportedError('package $packageName does not exist'); + } + var checkRoot = root; + if (subDir != null) { + checkRoot = root.resolve(subDir); + } + final dir = Directory.fromUri(checkRoot); + if (!await dir.exists()) { + throw UnsupportedError('can not resolve $subDir in $packageName'); + } + // A directory's modification time is not helpful because one of + // internal files may be modified later. + // In case of git / pub package we might be able to check pubspec, but no + // such technique applies for path packages. + await for (final entry in dir.list(recursive: true)) { + final stat = await entry.stat(); + if (stat.modified.isAfter(time)) { + return true; + } + } + return false; +} diff --git a/pkgs/jnigen/lib/src/util/string_util.dart b/pkgs/jnigen/lib/src/util/string_util.dart new file mode 100644 index 000000000..5a65bfb47 --- /dev/null +++ b/pkgs/jnigen/lib/src/util/string_util.dart @@ -0,0 +1,13 @@ +// Copyright (c) 2023, 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. + +extension StringUtil on String { + /// Makes the first letter uppercase. + String capitalize() { + return '${this[0].toUpperCase()}${substring(1)}'; + } + + /// Reverses an ASCII string. + String get reversed => split('').reversed.join(); +} diff --git a/pkgs/jnigen/lib/tools.dart b/pkgs/jnigen/lib/tools.dart new file mode 100644 index 000000000..252e4b7e7 --- /dev/null +++ b/pkgs/jnigen/lib/tools.dart @@ -0,0 +1,7 @@ +// 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. + +library jnigen_tools; + +export 'src/tools/tools.dart'; diff --git a/pkgs/jnigen/pubspec.yaml b/pkgs/jnigen/pubspec.yaml new file mode 100644 index 000000000..35e01bc2e --- /dev/null +++ b/pkgs/jnigen/pubspec.yaml @@ -0,0 +1,37 @@ +# 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. + +name: jnigen +description: A Dart bindings generator for Java and Kotlin that uses JNI under the hood to interop with Java virtual machine. +version: 0.8.0-wip +repository: https://github.com/dart-lang/jnigen/tree/main/jnigen + +environment: + sdk: ">=3.1.0 <4.0.0" + +topics: + - interop + - ffi + - codegen + - java + - jni + +dependencies: + json_annotation: ^4.8.0 + package_config: ^2.1.0 + path: ^1.8.0 + pub_semver: ^2.1.4 + args: ^2.3.0 + yaml: ^3.1.0 + logging: ^1.0.2 + meta: ^1.8.0 + cli_config: ^0.1.0 + +dev_dependencies: + lints: ^2.0.0 + jni: + path: ../jni + test: ^1.24.1 + build_runner: ^2.2.0 + json_serializable: ^6.6.0 diff --git a/pkgs/jnigen/test/.gitignore b/pkgs/jnigen/test/.gitignore new file mode 100644 index 000000000..36f1ec5bc --- /dev/null +++ b/pkgs/jnigen/test/.gitignore @@ -0,0 +1,4 @@ +# TODO(#166): Remove this. +!jni.jar +runtime_test_registrant_dartonly_generated.dart +generated_runtime_test.dart \ No newline at end of file diff --git a/pkgs/jnigen/test/README.md b/pkgs/jnigen/test/README.md new file mode 100644 index 000000000..e3ada8345 --- /dev/null +++ b/pkgs/jnigen/test/README.md @@ -0,0 +1,13 @@ +## How to run tests? +#### One-time setup: +``` +dart run jnigen:setup +``` + +#### Running tests +```sh +dart run tool/generate_runtime_tests.dart ## Regenerates runtime test files +dart test +``` + +Note: Tests fail if summarizer is not previously built and 2 tests try to build it concurrently. We have to address it using a lock file and exponential backoff (#43). Temporarily, run `dart run jnigen:setup` before running tests for the first time. diff --git a/pkgs/jnigen/test/config_test.dart b/pkgs/jnigen/test/config_test.dart new file mode 100644 index 000000000..ae2f9871e --- /dev/null +++ b/pkgs/jnigen/test/config_test.dart @@ -0,0 +1,141 @@ +// 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. + +import 'dart:io'; + +import 'package:jnigen/src/config/config.dart'; +import 'package:test/test.dart'; +import 'package:path/path.dart' hide equals; +import 'package:path/path.dart' as path show equals; + +import 'jackson_core_test/generate.dart'; +import 'test_util/test_util.dart'; + +const packageTests = 'test'; +final jacksonCoreTests = absolute(packageTests, 'jackson_core_test'); +final thirdParty = absolute(jacksonCoreTests, 'third_party'); +final lib = absolute(thirdParty, 'c_based', 'dart_bindings'); +final src = absolute(thirdParty, 'c_based', 'c_bindings'); +final testLib = absolute(thirdParty, 'test_', 'c_based', 'dart_bindings'); +final testSrc = absolute(thirdParty, 'test_', 'c_based', 'c_bindings'); + +/// Compares 2 [Config] objects using [expect] to give useful errors when +/// two fields are not equal. +void expectConfigsAreEqual(Config a, Config b) { + expect(a.classes, equals(b.classes), reason: "classes"); + expect(a.outputConfig.cConfig?.libraryName, + equals(b.outputConfig.cConfig?.libraryName), + reason: "libraryName"); + expect(a.outputConfig.cConfig?.path, equals(b.outputConfig.cConfig?.path), + reason: "cRoot"); + expect(a.outputConfig.dartConfig.path, equals(b.outputConfig.dartConfig.path), + reason: "dartRoot"); + expect(a.outputConfig.symbolsConfig?.path, + equals(b.outputConfig.symbolsConfig?.path), + reason: "symbolsRoot"); + expect(a.sourcePath, equals(b.sourcePath), reason: "sourcePath"); + expect(a.experiments, equals(b.experiments), reason: "experiments"); + expect(a.classPath, equals(b.classPath), reason: "classPath"); + expect(a.preamble, equals(b.preamble), reason: "preamble"); + final am = a.mavenDownloads; + final bm = b.mavenDownloads; + if (am != null) { + expect(bm, isNotNull); + expect(am.sourceDeps, bm!.sourceDeps, reason: "mavenDownloads.sourceDeps"); + expect(path.equals(am.sourceDir, bm.sourceDir), isTrue, + reason: "mavenDownloads.sourceDir"); + expect(am.jarOnlyDeps, bm.jarOnlyDeps, + reason: "mavenDownloads.jarOnlyDeps"); + expect(path.equals(am.jarDir, bm.jarDir), isTrue, + reason: "mavenDownloads.jarDir"); + } else { + expect(bm, isNull, reason: "mavenDownloads"); + } + final aa = a.androidSdkConfig; + final ba = b.androidSdkConfig; + if (aa != null) { + expect(ba, isNotNull, reason: "androidSdkConfig"); + expect(aa.versions, ba!.versions, reason: "androidSdkConfig.versions"); + expect(aa.sdkRoot, ba.sdkRoot, reason: "androidSdkConfig.sdkRoot"); + } else { + expect(ba, isNull, reason: "androidSdkConfig"); + } + final aso = a.summarizerOptions; + final bso = b.summarizerOptions; + if (aso != null) { + expect(bso, isNotNull, reason: "summarizerOptions"); + expect(aso.extraArgs, bso!.extraArgs, + reason: "summarizerOptions.extraArgs"); + expect(aso.workingDirectory, bso.workingDirectory, + reason: "summarizerOptions.workingDirectory"); + expect(aso.backend, bso.backend, reason: "summarizerOptions.backend"); + } else { + expect(bso, isNull, reason: "summarizerOptions"); + } +} + +final jnigenYaml = join(jacksonCoreTests, 'jnigen.yaml'); + +Config parseYamlConfig({List overrides = const []}) => + Config.parseArgs(['--config', jnigenYaml, ...overrides]); + +void testForErrorChecking( + {required String name, + required List overrides, + dynamic Function(Config)? function}) { + test(name, () { + expect( + () { + final config = parseYamlConfig(overrides: overrides); + if (function != null) { + function(config); + } + }, + throwsA(isA()), + ); + }); +} + +void main() async { + await checkLocallyBuiltDependencies(); + final config = Config.parseArgs([ + '--config', + jnigenYaml, + '-Doutput.c.path=$testSrc${Platform.pathSeparator}', + '-Doutput.dart.path=$testLib${Platform.pathSeparator}', + ]); + + test('compare configuration values', () { + expectConfigsAreEqual( + config, + getConfig( + root: join(thirdParty, 'test_'), + bindingsType: BindingsType.cBased, + ), + ); + }); + + group('Test for config error checking', () { + testForErrorChecking( + name: 'Invalid bindings type', + overrides: ['-Doutput.bindings_type=c_base'], + ); + testForErrorChecking( + name: 'Invalid output structure', + overrides: ['-Doutput.dart.structure=singl_file'], + ); + testForErrorChecking( + name: 'Dart path not ending with /', + overrides: ['-Doutput.dart.path=lib'], + ); + testForErrorChecking( + name: 'Invalid log level', + overrides: ['-Dlog_level=inf'], + ); + testForErrorChecking( + name: 'Nested class specified', + overrides: ['-Dclasses=com.android.Clock\$Clock'], + ); + }); +} diff --git a/pkgs/jnigen/test/dart_generator_test.dart b/pkgs/jnigen/test/dart_generator_test.dart new file mode 100644 index 000000000..e9bbb7608 --- /dev/null +++ b/pkgs/jnigen/test/dart_generator_test.dart @@ -0,0 +1,21 @@ +// Copyright (c) 2023, 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. + +import 'package:jnigen/src/bindings/dart_generator.dart'; +import 'package:test/test.dart'; + +import 'test_util/test_util.dart'; + +void main() async { + await checkLocallyBuiltDependencies(); + + test('OutsideInBuffer', () { + final buffer = OutsideInBuffer(); + buffer.appendLeft('f('); + buffer.prependRight('x)'); + buffer.appendLeft('g('); + buffer.prependRight('y) + '); + expect(buffer.toString(), 'f(g(y) + x)'); + }); +} diff --git a/pkgs/jnigen/test/descriptor_test.dart b/pkgs/jnigen/test/descriptor_test.dart new file mode 100644 index 000000000..f1b906034 --- /dev/null +++ b/pkgs/jnigen/test/descriptor_test.dart @@ -0,0 +1,42 @@ +// Copyright (c) 2023, 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. + +import 'package:jnigen/src/bindings/descriptor.dart'; +import 'package:jnigen/src/bindings/linker.dart'; +import 'package:jnigen/src/bindings/unnester.dart'; +import 'package:jnigen/src/config/config_types.dart'; +import 'package:jnigen/src/summary/summary.dart'; +import 'package:test/test.dart'; + +import 'simple_package_test/generate.dart' as simple_package_test; +import 'kotlin_test/generate.dart' as kotlin_test; +import 'jackson_core_test/generate.dart' as jackson_core_test; +import 'test_util/test_util.dart'; + +void main() { + checkLocallyBuiltDependencies(); + for (final (name, getConfig) in [ + ('simple_package', simple_package_test.getConfig), + ('kotlin', kotlin_test.getConfig), + ('jackson_core', jackson_core_test.getConfig), + ]) { + test('Method descriptor generation for $name', + timeout: const Timeout.factor(3), () async { + final config = getConfig(); + config.summarizerOptions = + SummarizerOptions(backend: SummarizerBackend.asm); + final classes = await getSummary(config); + await classes.accept(Linker(config)); + classes.accept(const Unnester()); + for (final decl in classes.decls.values) { + // Checking if the descriptor from ASM matches the one generated by + // [MethodDescriptor]. + final methodDescriptor = MethodDescriptor(decl.allTypeParams); + for (final method in decl.methods) { + expect(method.descriptor, method.accept(methodDescriptor)); + } + } + }); + } +} diff --git a/pkgs/jnigen/test/jackson_core_test/.gitignore b/pkgs/jnigen/test/jackson_core_test/.gitignore new file mode 100644 index 000000000..02158123c --- /dev/null +++ b/pkgs/jnigen/test/jackson_core_test/.gitignore @@ -0,0 +1,5 @@ +*.jar +third_party/jar/** +third_party/java/** +third_party/test_lib/ +third_party/test_src/ diff --git a/pkgs/jnigen/test/jackson_core_test/generate.dart b/pkgs/jnigen/test/jackson_core_test/generate.dart new file mode 100644 index 000000000..796a760ca --- /dev/null +++ b/pkgs/jnigen/test/jackson_core_test/generate.dart @@ -0,0 +1,93 @@ +// 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. + +import 'package:jnigen/jnigen.dart'; +import 'package:jnigen/src/config/experiments.dart'; +import 'package:logging/logging.dart'; +import 'package:path/path.dart' hide equals; + +const jacksonPreamble = '// Generated from jackson-core which is licensed under' + ' the Apache License 2.0.\n' + '// The following copyright from the original authors applies.\n' + '// See https://github.com/FasterXML/jackson-core/blob/2.14/LICENSE\n' + '//\n' + '// Copyright (c) 2007 - The Jackson Project Authors\n' + '// Licensed under the Apache License, Version 2.0 (the "License")\n' + '// you may not use this file except in compliance with the License.\n' + '// You may obtain a copy of the License at\n' + '//\n' + '// http://www.apache.org/licenses/LICENSE-2.0\n' + '//\n' + '// Unless required by applicable law or agreed to in writing, software\n' + '// distributed under the License is distributed on an "AS IS" BASIS,\n' + '// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n' + '// See the License for the specific language governing permissions and\n' + '// limitations under the License.\n'; + +const testName = 'jackson_core_test'; +final thirdPartyDir = join('test', testName, 'third_party'); +const deps = ['com.fasterxml.jackson.core:jackson-core:2.13.4']; + +Config getConfig({ + String? root, + bool generateFullVersion = false, + bool useAsm = false, + BindingsType bindingsType = BindingsType.dartOnly, +}) { + final rootDir = root ?? thirdPartyDir; + final bindingTypeDir = bindingsType.getConfigString(); + final config = Config( + mavenDownloads: MavenDownloads( + sourceDeps: deps, + sourceDir: join(thirdPartyDir, 'java'), + jarDir: join(thirdPartyDir, 'jar'), + ), + summarizerOptions: SummarizerOptions( + backend: useAsm ? SummarizerBackend.asm : null, + ), + preamble: jacksonPreamble, + outputConfig: OutputConfig( + bindingsType: bindingsType, + // Have to be judicious here, and ensure null when bindings type is + // dart-only, because config-test is also using this. + cConfig: bindingsType == BindingsType.cBased + ? CCodeOutputConfig( + libraryName: 'jackson_core', + path: Uri.directory(join(rootDir, bindingTypeDir, 'c_bindings')), + ) + : null, + dartConfig: DartCodeOutputConfig( + path: Uri.directory(join(rootDir, bindingTypeDir, 'dart_bindings')), + ), + ), + classes: (generateFullVersion) + ? ['com.fasterxml.jackson.core'] + : [ + 'com.fasterxml.jackson.core.JsonFactory', + 'com.fasterxml.jackson.core.JsonParser', + 'com.fasterxml.jackson.core.JsonToken', + ], + logLevel: Level.INFO, + exclude: BindingExclusions( + // TODO(#31): Remove field exclusions. + fields: excludeAll([ + ['com.fasterxml.jackson.core.JsonFactory', 'DEFAULT_QUOTE_CHAR'], + ['com.fasterxml.jackson.core.Base64Variant', 'PADDING_CHAR_NONE'], + ['com.fasterxml.jackson.core.base.ParserMinimalBase', 'CHAR_NULL'], + ['com.fasterxml.jackson.core.io.UTF32Reader', 'NC'], + ]), + // TODO(#159): Remove class exclusions. + classes: ClassNameFilter.exclude( + 'com.fasterxml.jackson.core.JsonFactoryBuilder', + ), + ), + experiments: {Experiment.interfaceImplementation}, + ); + return config; +} + +void main() async { + await generateJniBindings(getConfig(bindingsType: BindingsType.cBased)); + await generateJniBindings(getConfig(bindingsType: BindingsType.dartOnly)); +} diff --git a/pkgs/jnigen/test/jackson_core_test/generated_files_test.dart b/pkgs/jnigen/test/jackson_core_test/generated_files_test.dart new file mode 100644 index 000000000..818e5d071 --- /dev/null +++ b/pkgs/jnigen/test/jackson_core_test/generated_files_test.dart @@ -0,0 +1,37 @@ +// 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. + +import 'package:test/test.dart'; + +import 'package:jnigen/jnigen.dart'; + +import '../test_util/test_util.dart'; +import 'generate.dart'; + +void main() async { + await checkLocallyBuiltDependencies(); + + generateAndCompareBothModes( + 'Generate and compare bindings for jackson_core library', + getConfig(bindingsType: BindingsType.cBased), + getConfig(bindingsType: BindingsType.dartOnly), + ); + test( + 'generate and analyze bindings for complete library, ' + 'not just required classes', () async { + final config = getConfig(generateFullVersion: true); + await generateAndAnalyzeBindings(config); + }, timeout: const Timeout(Duration(minutes: 2)), tags: largeTestTag); + + test('generate and analyze bindings using ASM', () async { + final config = getConfig(generateFullVersion: true, useAsm: true); + await generateAndAnalyzeBindings(config); + }, timeout: const Timeout(Duration(minutes: 2)), tags: largeTestTag); + + test('Generate and analyze pure dart bindings', () async { + final config = getConfig(generateFullVersion: true); + config.outputConfig.bindingsType = BindingsType.dartOnly; + await generateAndAnalyzeBindings(config); + }, timeout: const Timeout.factor(2), tags: largeTestTag); +} diff --git a/pkgs/jnigen/test/jackson_core_test/jnigen.yaml b/pkgs/jnigen/test/jackson_core_test/jnigen.yaml new file mode 100644 index 000000000..cf3b4db15 --- /dev/null +++ b/pkgs/jnigen/test/jackson_core_test/jnigen.yaml @@ -0,0 +1,48 @@ +maven_downloads: + source_deps: + - 'com.fasterxml.jackson.core:jackson-core:2.13.4' + source_dir: third_party/java/ + jar_dir: third_party/jar/ + +output: + bindings_type: c_based + c: + library_name: jackson_core + path: third_party/c_based/c_bindings/ + dart: + path: third_party/c_based/dart_bindings/ + +classes: + - 'com.fasterxml.jackson.core.JsonFactory' + - 'com.fasterxml.jackson.core.JsonParser' + - 'com.fasterxml.jackson.core.JsonToken' + +exclude: + fields: + - 'com.fasterxml.jackson.core.JsonFactory#DEFAULT_QUOTE_CHAR' + - 'com.fasterxml.jackson.core.Base64Variant#PADDING_CHAR_NONE' + - 'com.fasterxml.jackson.core.base.ParserMinimalBase#CHAR_NULL' + - 'com.fasterxml.jackson.core.io.UTF32Reader#NC' + +preamble: | + // Generated from jackson-core which is licensed under the Apache License 2.0. + // The following copyright from the original authors applies. + // See https://github.com/FasterXML/jackson-core/blob/2.14/LICENSE + // + // Copyright (c) 2007 - The Jackson Project Authors + // Licensed under the Apache License, Version 2.0 (the "License") + // you may not use this file except in compliance with the License. + // You may obtain a copy of the License at + // + // http://www.apache.org/licenses/LICENSE-2.0 + // + // Unless required by applicable law or agreed to in writing, software + // distributed under the License is distributed on an "AS IS" BASIS, + // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + // See the License for the specific language governing permissions and + // limitations under the License. + +log_level: warning + +enable_experiment: + - interface_implementation diff --git a/pkgs/jnigen/test/jackson_core_test/runtime_test_registrant.dart b/pkgs/jnigen/test/jackson_core_test/runtime_test_registrant.dart new file mode 100644 index 000000000..28e6c2b6c --- /dev/null +++ b/pkgs/jnigen/test/jackson_core_test/runtime_test_registrant.dart @@ -0,0 +1,44 @@ +// 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. + +import 'package:test/test.dart'; +import 'package:jni/jni.dart'; + +import '../test_util/callback_types.dart'; + +import 'third_party/c_based/dart_bindings/com/fasterxml/jackson/core/_package.dart'; + +// This file doesn't define main, because only one JVM has to be spawned with +// all classpaths, it's managed at a different file which calls these tests. + +void registerTests(String groupName, TestRunnerCallback test) { + group(groupName, () { + test('simple json parsing test', () { + final json = JString.fromString('[1, true, false, 2, 4]'); + JsonFactory factory; + factory = JsonFactory(); + final parser = factory.createParser6(json); + final values = []; + while (!parser.isClosed()) { + final next = parser.nextToken(); + if (next.isNull) continue; + values.add(next.isNumeric()); + next.release(); + } + expect(values, equals([false, true, false, false, true, true, false])); + for (final obj in [factory, parser, json]) { + obj.release(); + } + }); + test("parsing invalid JSON throws JniException", () { + using((arena) { + final factory = JsonFactory()..releasedBy(arena); + final erroneous = factory + .createParser6("".toJString()..releasedBy(arena)) + ..releasedBy(arena); + expect(() => erroneous.nextToken(), throwsA(isA())); + }); + }); + }); +} diff --git a/pkgs/jnigen/test/jackson_core_test/third_party/c_based/c_bindings/.clang-format b/pkgs/jnigen/test/jackson_core_test/third_party/c_based/c_bindings/.clang-format new file mode 100644 index 000000000..a256c2f09 --- /dev/null +++ b/pkgs/jnigen/test/jackson_core_test/third_party/c_based/c_bindings/.clang-format @@ -0,0 +1,15 @@ +# From dart SDK: https://github.com/dart-lang/sdk/blob/main/.clang-format + +# Defines the Chromium style for automatic reformatting. +# http://clang.llvm.org/docs/ClangFormatStyleOptions.html +BasedOnStyle: Chromium + +# clang-format doesn't seem to do a good job of this for longer comments. +ReflowComments: 'false' + +# We have lots of these. Though we need to put them all in curly braces, +# clang-format can't do that. +AllowShortIfStatementsOnASingleLine: 'true' + +# Put escaped newlines into the rightmost column. +AlignEscapedNewlinesLeft: false diff --git a/pkgs/jnigen/test/jackson_core_test/third_party/c_based/c_bindings/CMakeLists.txt b/pkgs/jnigen/test/jackson_core_test/third_party/c_based/c_bindings/CMakeLists.txt new file mode 100644 index 000000000..db216f524 --- /dev/null +++ b/pkgs/jnigen/test/jackson_core_test/third_party/c_based/c_bindings/CMakeLists.txt @@ -0,0 +1,32 @@ +# jni_native_build (Build with jni:setup. Do not delete this line.) + +# The Flutter tooling requires that developers have CMake 3.10 or later +# installed. You should not increase this version, as doing so will cause +# the plugin to fail to compile for some customers of the plugin. +cmake_minimum_required(VERSION 3.10) + +project(jackson_core VERSION 0.0.1 LANGUAGES C) + +add_library(jackson_core SHARED + "./jackson_core.c" +) + +set_target_properties(jackson_core PROPERTIES + OUTPUT_NAME "jackson_core" +) + +target_compile_definitions(jackson_core PUBLIC DART_SHARED_LIB) + +if(WIN32) + set_target_properties(${TARGET_NAME} PROPERTIES + LINK_FLAGS "/DELAYLOAD:jvm.dll") +endif() + +if (ANDROID) + target_link_libraries(jackson_core log) +else() + find_package(Java REQUIRED) + find_package(JNI REQUIRED) + include_directories(${JNI_INCLUDE_DIRS}) + target_link_libraries(jackson_core ${JNI_LIBRARIES}) +endif() diff --git a/pkgs/jnigen/test/jackson_core_test/third_party/c_based/c_bindings/dartjni.h b/pkgs/jnigen/test/jackson_core_test/third_party/c_based/c_bindings/dartjni.h new file mode 100644 index 000000000..8f1dc7481 --- /dev/null +++ b/pkgs/jnigen/test/jackson_core_test/third_party/c_based/c_bindings/dartjni.h @@ -0,0 +1,424 @@ +// 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. + +#pragma once + +// Note: include appropriate system jni.h as found by CMake, not third_party/jni.h. +#include +#include +#include +#include + +#if _WIN32 +#include +#else +#include +#include +#endif + +#if _WIN32 +#define FFI_PLUGIN_EXPORT __declspec(dllexport) +#else +#define FFI_PLUGIN_EXPORT +#endif + +#if defined _WIN32 +#define thread_local __declspec(thread) +#else +#define thread_local __thread +#endif + +#ifdef __ANDROID__ +#include +#endif + +#ifdef __ANDROID__ +#define __ENVP_CAST (JNIEnv**) +#else +#define __ENVP_CAST (void**) +#endif + +/// Locking functions for windows and pthread. + +#if defined _WIN32 +#include + +typedef CRITICAL_SECTION MutexLock; +typedef CONDITION_VARIABLE ConditionVariable; + +static inline void init_lock(MutexLock* lock) { + InitializeCriticalSection(lock); +} + +static inline void acquire_lock(MutexLock* lock) { + EnterCriticalSection(lock); +} + +static inline void release_lock(MutexLock* lock) { + LeaveCriticalSection(lock); +} + +static inline void destroy_lock(MutexLock* lock) { + DeleteCriticalSection(lock); +} + +static inline void init_cond(ConditionVariable* cond) { + InitializeConditionVariable(cond); +} + +static inline void signal_cond(ConditionVariable* cond) { + WakeConditionVariable(cond); +} + +static inline void wait_for(ConditionVariable* cond, MutexLock* lock) { + SleepConditionVariableCS(cond, lock, INFINITE); +} + +static inline void destroy_cond(ConditionVariable* cond) { + // Not available. +} + +#elif defined __APPLE__ || defined __LINUX__ || defined __ANDROID__ || \ + defined __GNUC__ +#include + +typedef pthread_mutex_t MutexLock; +typedef pthread_cond_t ConditionVariable; + +static inline void init_lock(MutexLock* lock) { + pthread_mutex_init(lock, NULL); +} + +static inline void acquire_lock(MutexLock* lock) { + pthread_mutex_lock(lock); +} + +static inline void release_lock(MutexLock* lock) { + pthread_mutex_unlock(lock); +} + +static inline void destroy_lock(MutexLock* lock) { + pthread_mutex_destroy(lock); +} + +static inline void init_cond(ConditionVariable* cond) { + pthread_cond_init(cond, NULL); +} + +static inline void signal_cond(ConditionVariable* cond) { + pthread_cond_signal(cond); +} + +static inline void wait_for(ConditionVariable* cond, MutexLock* lock) { + pthread_cond_wait(cond, lock); +} + +static inline void destroy_cond(ConditionVariable* cond) { + pthread_cond_destroy(cond); +} + +#else + +#error "No locking/condition variable support; Possibly unsupported platform" + +#endif + +typedef struct CallbackResult { + MutexLock lock; + ConditionVariable cond; + int ready; + jobject object; +} CallbackResult; + +typedef struct JniLocks { + MutexLock classLoadingLock; + MutexLock methodLoadingLock; + MutexLock fieldLoadingLock; +} JniLocks; + +/// Represents the error when dart-jni layer has already spawned singleton VM. +#define DART_JNI_SINGLETON_EXISTS (-99); + +/// Stores the global state of the JNI. +typedef struct JniContext { + JavaVM* jvm; + jobject classLoader; + jmethodID loadClassMethod; + jobject currentActivity; + jobject appContext; + JniLocks locks; +} JniContext; + +// jniEnv for this thread, used by inline functions in this header, +// therefore declared as extern. +extern thread_local JNIEnv* jniEnv; + +extern JniContext* jni; + +/// Types used by JNI API to distinguish between primitive types. +enum JniType { + booleanType = 0, + byteType = 1, + shortType = 2, + charType = 3, + intType = 4, + longType = 5, + floatType = 6, + doubleType = 7, + objectType = 8, + voidType = 9, +}; + +/// Result type for use by JNI. +/// +/// If [exception] is null, it means the result is valid. +/// It's assumed that the caller knows the expected type in [result]. +typedef struct JniResult { + jvalue value; + jthrowable exception; +} JniResult; + +/// Similar to [JniResult] but for class lookups. +typedef struct JniClassLookupResult { + jclass value; + jthrowable exception; +} JniClassLookupResult; + +/// Similar to [JniResult] but for method/field ID lookups. +typedef struct JniPointerResult { + const void* value; + jthrowable exception; +} JniPointerResult; + +/// JniExceptionDetails holds 2 jstring objects, one is the result of +/// calling `toString` on exception object, other is stack trace; +typedef struct JniExceptionDetails { + jstring message; + jstring stacktrace; +} JniExceptionDetails; + +/// This struct contains functions which wrap method call / field access conveniently along with +/// exception checking. +/// +/// Flutter embedding checks for pending JNI exceptions before an FFI transition, which requires us +/// to check for and clear the exception before returning to dart code, which requires these functions +/// to return result types. +typedef struct JniAccessorsStruct { + JniClassLookupResult (*getClass)(char* internalName); + JniPointerResult (*getFieldID)(jclass cls, char* fieldName, char* signature); + JniPointerResult (*getStaticFieldID)(jclass cls, + char* fieldName, + char* signature); + JniPointerResult (*getMethodID)(jclass cls, + char* methodName, + char* signature); + JniPointerResult (*getStaticMethodID)(jclass cls, + char* methodName, + char* signature); + JniResult (*newObject)(jclass cls, jmethodID ctor, jvalue* args); + JniResult (*newPrimitiveArray)(jsize length, int type); + JniResult (*newObjectArray)(jsize length, + jclass elementClass, + jobject initialElement); + JniResult (*getArrayElement)(jarray array, int index, int type); + JniResult (*callMethod)(jobject obj, + jmethodID methodID, + int callType, + jvalue* args); + JniResult (*callStaticMethod)(jclass cls, + jmethodID methodID, + int callType, + jvalue* args); + JniResult (*getField)(jobject obj, jfieldID fieldID, int callType); + JniResult (*getStaticField)(jclass cls, jfieldID fieldID, int callType); + JniExceptionDetails (*getExceptionDetails)(jthrowable exception); +} JniAccessorsStruct; + +FFI_PLUGIN_EXPORT JniAccessorsStruct* GetAccessors(); + +FFI_PLUGIN_EXPORT JavaVM* GetJavaVM(void); + +FFI_PLUGIN_EXPORT JNIEnv* GetJniEnv(void); + +/// Spawn a JVM with given arguments. +/// +/// Returns JNI_OK on success, and one of the documented JNI error codes on +/// failure. It returns DART_JNI_SINGLETON_EXISTS if an attempt to spawn multiple +/// JVMs is made, even if the underlying API potentially supports multiple VMs. +FFI_PLUGIN_EXPORT int SpawnJvm(JavaVMInitArgs* args); + +/// Load class through platform-specific mechanism. +/// +/// Currently uses application classloader on android, +/// and JNIEnv->FindClass on other platforms. +FFI_PLUGIN_EXPORT jclass FindClass(const char* name); + +/// Returns Application classLoader (on Android), +/// which can be used to load application and platform classes. +/// +/// On other platforms, NULL is returned. +FFI_PLUGIN_EXPORT jobject GetClassLoader(void); + +/// Returns application context on Android. +/// +/// On other platforms, NULL is returned. +FFI_PLUGIN_EXPORT jobject GetApplicationContext(void); + +/// Returns current activity of the app on Android. +FFI_PLUGIN_EXPORT jobject GetCurrentActivity(void); + +static inline void attach_thread() { + if (jniEnv == NULL) { + (*jni->jvm)->AttachCurrentThread(jni->jvm, __ENVP_CAST & jniEnv, NULL); + } +} + +/// Load class into [cls] using platform specific mechanism +static inline void load_class_platform(jclass* cls, const char* name) { +#ifdef __ANDROID__ + jstring className = (*jniEnv)->NewStringUTF(jniEnv, name); + *cls = (*jniEnv)->CallObjectMethod(jniEnv, jni->classLoader, + jni->loadClassMethod, className); + (*jniEnv)->DeleteLocalRef(jniEnv, className); +#else + *cls = (*jniEnv)->FindClass(jniEnv, name); +#endif +} + +static inline void load_class_local_ref(jclass* cls, const char* name) { + if (*cls == NULL) { + acquire_lock(&jni->locks.classLoadingLock); + if (*cls == NULL) { + load_class_platform(cls, name); + } + release_lock(&jni->locks.classLoadingLock); + } +} + +static inline void load_class_global_ref(jclass* cls, const char* name) { + if (*cls == NULL) { + jclass tmp = NULL; + acquire_lock(&jni->locks.classLoadingLock); + if (*cls == NULL) { + load_class_platform(&tmp, name); + if (!(*jniEnv)->ExceptionCheck(jniEnv)) { + *cls = (*jniEnv)->NewGlobalRef(jniEnv, tmp); + (*jniEnv)->DeleteLocalRef(jniEnv, tmp); + } + } + release_lock(&jni->locks.classLoadingLock); + } +} + +static inline void load_method(jclass cls, + jmethodID* res, + const char* name, + const char* sig) { + if (*res == NULL) { + acquire_lock(&jni->locks.methodLoadingLock); + if (*res == NULL) { + *res = (*jniEnv)->GetMethodID(jniEnv, cls, name, sig); + } + release_lock(&jni->locks.methodLoadingLock); + } +} + +static inline void load_static_method(jclass cls, + jmethodID* res, + const char* name, + const char* sig) { + if (*res == NULL) { + acquire_lock(&jni->locks.methodLoadingLock); + if (*res == NULL) { + *res = (*jniEnv)->GetStaticMethodID(jniEnv, cls, name, sig); + } + release_lock(&jni->locks.methodLoadingLock); + } +} + +static inline void load_field(jclass cls, + jfieldID* res, + const char* name, + const char* sig) { + if (*res == NULL) { + acquire_lock(&jni->locks.fieldLoadingLock); + if (*res == NULL) { + *res = (*jniEnv)->GetFieldID(jniEnv, cls, name, sig); + } + release_lock(&jni->locks.fieldLoadingLock); + } +} + +static inline void load_static_field(jclass cls, + jfieldID* res, + const char* name, + const char* sig) { + if (*res == NULL) { + acquire_lock(&jni->locks.fieldLoadingLock); + if (*res == NULL) { + *res = (*jniEnv)->GetStaticFieldID(jniEnv, cls, name, sig); + } + release_lock(&jni->locks.fieldLoadingLock); + } +} + +static inline jobject to_global_ref(jobject ref) { + jobject g = (*jniEnv)->NewGlobalRef(jniEnv, ref); + (*jniEnv)->DeleteLocalRef(jniEnv, ref); + return g; +} + +// These functions are useful for C+Dart bindings, and not required for pure dart bindings. + +FFI_PLUGIN_EXPORT JniContext* GetJniContextPtr(); + +/// For use by jni_gen's generated code +/// don't use these. + +// these 2 fn ptr vars will be defined by generated code library +extern JniContext* (*context_getter)(void); +extern JNIEnv* (*env_getter)(void); + +// this function will be exported by generated code library +// it will set above 2 variables. +FFI_PLUGIN_EXPORT void setJniGetters(struct JniContext* (*cg)(void), + JNIEnv* (*eg)(void)); + +static inline void load_env() { + if (jniEnv == NULL) { + jni = context_getter(); + jniEnv = env_getter(); + } +} + +static inline jthrowable check_exception() { + jthrowable exception = (*jniEnv)->ExceptionOccurred(jniEnv); + if (exception != NULL) (*jniEnv)->ExceptionClear(jniEnv); + if (exception == NULL) return NULL; + return to_global_ref(exception); +} + +static inline JniResult to_global_ref_result(jobject ref) { + JniResult result; + result.exception = check_exception(); + if (result.exception == NULL) { + result.value.l = to_global_ref(ref); + } + return result; +} + +FFI_PLUGIN_EXPORT intptr_t InitDartApiDL(void* data); + +FFI_PLUGIN_EXPORT +JniResult DartException__ctor(jstring message); + +FFI_PLUGIN_EXPORT +JniResult PortContinuation__ctor(int64_t j); + +FFI_PLUGIN_EXPORT +JniResult PortProxy__newInstance(jobject binaryName, + int64_t port, + int64_t functionPtr); + +FFI_PLUGIN_EXPORT void resultFor(CallbackResult* result, jobject object); diff --git a/pkgs/jnigen/test/jackson_core_test/third_party/c_based/c_bindings/jackson_core.c b/pkgs/jnigen/test/jackson_core_test/third_party/c_based/c_bindings/jackson_core.c new file mode 100644 index 000000000..3203612ea --- /dev/null +++ b/pkgs/jnigen/test/jackson_core_test/third_party/c_based/c_bindings/jackson_core.c @@ -0,0 +1,3729 @@ +// Generated from jackson-core which is licensed under the Apache License 2.0. +// The following copyright from the original authors applies. +// See https://github.com/FasterXML/jackson-core/blob/2.14/LICENSE +// +// Copyright (c) 2007 - The Jackson Project Authors +// Licensed under the Apache License, Version 2.0 (the "License") +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Autogenerated by jnigen. DO NOT EDIT! + +#include +#include "dartjni.h" +#include "jni.h" + +thread_local JNIEnv* jniEnv; +JniContext* jni; + +JniContext* (*context_getter)(void); +JNIEnv* (*env_getter)(void); + +void setJniGetters(JniContext* (*cg)(void), JNIEnv* (*eg)(void)) { + context_getter = cg; + env_getter = eg; +} + +// com.fasterxml.jackson.core.JsonFactory +jclass _c_JsonFactory = NULL; + +jmethodID _m_JsonFactory__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__new0() { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__new0, "", "()V"); + if (_m_JsonFactory__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->NewObject(jniEnv, _c_JsonFactory, _m_JsonFactory__new0); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__new1 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__new1(jobject oc) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__new1, "", + "(Lcom/fasterxml/jackson/core/ObjectCodec;)V"); + if (_m_JsonFactory__new1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->NewObject(jniEnv, _c_JsonFactory, _m_JsonFactory__new1, oc); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__new2 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__new2(jobject src, jobject codec) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__new2, "", + "(Lcom/fasterxml/jackson/core/JsonFactory;Lcom/fasterxml/jackson/" + "core/ObjectCodec;)V"); + if (_m_JsonFactory__new2 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject(jniEnv, _c_JsonFactory, + _m_JsonFactory__new2, src, codec); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__new3 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__new3(jobject b) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__new3, "", + "(Lcom/fasterxml/jackson/core/JsonFactoryBuilder;)V"); + if (_m_JsonFactory__new3 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->NewObject(jniEnv, _c_JsonFactory, _m_JsonFactory__new3, b); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__new4 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__new4(jobject b, uint8_t bogus) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__new4, "", + "(Lcom/fasterxml/jackson/core/TSFBuilder;Z)V"); + if (_m_JsonFactory__new4 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject(jniEnv, _c_JsonFactory, + _m_JsonFactory__new4, b, bogus); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__rebuild = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__rebuild(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__rebuild, "rebuild", + "()Lcom/fasterxml/jackson/core/TSFBuilder;"); + if (_m_JsonFactory__rebuild == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_JsonFactory__rebuild); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__builder = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__builder() { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_JsonFactory, &_m_JsonFactory__builder, "builder", + "()Lcom/fasterxml/jackson/core/TSFBuilder;"); + if (_m_JsonFactory__builder == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod(jniEnv, _c_JsonFactory, + _m_JsonFactory__builder); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__copy = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__copy(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__copy, "copy", + "()Lcom/fasterxml/jackson/core/JsonFactory;"); + if (_m_JsonFactory__copy == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_JsonFactory__copy); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__readResolve = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__readResolve(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__readResolve, "readResolve", + "()Ljava/lang/Object;"); + if (_m_JsonFactory__readResolve == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_JsonFactory__readResolve); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__requiresPropertyOrdering = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__requiresPropertyOrdering(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__requiresPropertyOrdering, + "requiresPropertyOrdering", "()Z"); + if (_m_JsonFactory__requiresPropertyOrdering == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod( + jniEnv, self_, _m_JsonFactory__requiresPropertyOrdering); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonFactory__canHandleBinaryNatively = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__canHandleBinaryNatively(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__canHandleBinaryNatively, + "canHandleBinaryNatively", "()Z"); + if (_m_JsonFactory__canHandleBinaryNatively == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod( + jniEnv, self_, _m_JsonFactory__canHandleBinaryNatively); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonFactory__canUseCharArrays = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__canUseCharArrays(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__canUseCharArrays, + "canUseCharArrays", "()Z"); + if (_m_JsonFactory__canUseCharArrays == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod( + jniEnv, self_, _m_JsonFactory__canUseCharArrays); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonFactory__canParseAsync = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__canParseAsync(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__canParseAsync, "canParseAsync", + "()Z"); + if (_m_JsonFactory__canParseAsync == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod(jniEnv, self_, + _m_JsonFactory__canParseAsync); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonFactory__getFormatReadFeatureType = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__getFormatReadFeatureType(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__getFormatReadFeatureType, + "getFormatReadFeatureType", "()Ljava/lang/Class;"); + if (_m_JsonFactory__getFormatReadFeatureType == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__getFormatReadFeatureType); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__getFormatWriteFeatureType = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__getFormatWriteFeatureType(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__getFormatWriteFeatureType, + "getFormatWriteFeatureType", "()Ljava/lang/Class;"); + if (_m_JsonFactory__getFormatWriteFeatureType == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__getFormatWriteFeatureType); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__canUseSchema = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__canUseSchema(jobject self_, jobject schema) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__canUseSchema, "canUseSchema", + "(Lcom/fasterxml/jackson/core/FormatSchema;)Z"); + if (_m_JsonFactory__canUseSchema == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod( + jniEnv, self_, _m_JsonFactory__canUseSchema, schema); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonFactory__getFormatName = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__getFormatName(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__getFormatName, "getFormatName", + "()Ljava/lang/String;"); + if (_m_JsonFactory__getFormatName == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_JsonFactory__getFormatName); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__hasFormat = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__hasFormat(jobject self_, jobject acc) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__hasFormat, "hasFormat", + "(Lcom/fasterxml/jackson/core/format/InputAccessor;)Lcom/" + "fasterxml/jackson/core/format/MatchStrength;"); + if (_m_JsonFactory__hasFormat == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod(jniEnv, self_, + _m_JsonFactory__hasFormat, acc); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__requiresCustomCodec = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__requiresCustomCodec(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__requiresCustomCodec, + "requiresCustomCodec", "()Z"); + if (_m_JsonFactory__requiresCustomCodec == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod( + jniEnv, self_, _m_JsonFactory__requiresCustomCodec); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonFactory__hasJSONFormat = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__hasJSONFormat(jobject self_, jobject acc) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__hasJSONFormat, "hasJSONFormat", + "(Lcom/fasterxml/jackson/core/format/InputAccessor;)Lcom/" + "fasterxml/jackson/core/format/MatchStrength;"); + if (_m_JsonFactory__hasJSONFormat == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__hasJSONFormat, acc); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__version = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__version(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__version, "version", + "()Lcom/fasterxml/jackson/core/Version;"); + if (_m_JsonFactory__version == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_JsonFactory__version); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__configure = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__configure(jobject self_, jobject f, uint8_t state) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__configure, "configure", + "(Lcom/fasterxml/jackson/core/JsonFactory$Feature;Z)Lcom/" + "fasterxml/jackson/core/JsonFactory;"); + if (_m_JsonFactory__configure == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__configure, f, state); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__enable = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__enable(jobject self_, jobject f) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__enable, "enable", + "(Lcom/fasterxml/jackson/core/JsonFactory$Feature;)Lcom/" + "fasterxml/jackson/core/JsonFactory;"); + if (_m_JsonFactory__enable == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_JsonFactory__enable, f); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__disable = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__disable(jobject self_, jobject f) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__disable, "disable", + "(Lcom/fasterxml/jackson/core/JsonFactory$Feature;)Lcom/" + "fasterxml/jackson/core/JsonFactory;"); + if (_m_JsonFactory__disable == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_JsonFactory__disable, f); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__isEnabled = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__isEnabled(jobject self_, jobject f) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__isEnabled, "isEnabled", + "(Lcom/fasterxml/jackson/core/JsonFactory$Feature;)Z"); + if (_m_JsonFactory__isEnabled == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = + (*jniEnv)->CallBooleanMethod(jniEnv, self_, _m_JsonFactory__isEnabled, f); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonFactory__getParserFeatures = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__getParserFeatures(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__getParserFeatures, + "getParserFeatures", "()I"); + if (_m_JsonFactory__getParserFeatures == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = (*jniEnv)->CallIntMethod(jniEnv, self_, + _m_JsonFactory__getParserFeatures); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonFactory__getGeneratorFeatures = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__getGeneratorFeatures(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__getGeneratorFeatures, + "getGeneratorFeatures", "()I"); + if (_m_JsonFactory__getGeneratorFeatures == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = (*jniEnv)->CallIntMethod( + jniEnv, self_, _m_JsonFactory__getGeneratorFeatures); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonFactory__getFormatParserFeatures = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__getFormatParserFeatures(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__getFormatParserFeatures, + "getFormatParserFeatures", "()I"); + if (_m_JsonFactory__getFormatParserFeatures == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = (*jniEnv)->CallIntMethod( + jniEnv, self_, _m_JsonFactory__getFormatParserFeatures); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonFactory__getFormatGeneratorFeatures = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__getFormatGeneratorFeatures(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__getFormatGeneratorFeatures, + "getFormatGeneratorFeatures", "()I"); + if (_m_JsonFactory__getFormatGeneratorFeatures == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = (*jniEnv)->CallIntMethod( + jniEnv, self_, _m_JsonFactory__getFormatGeneratorFeatures); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonFactory__configure1 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__configure1(jobject self_, jobject f, uint8_t state) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__configure1, "configure", + "(Lcom/fasterxml/jackson/core/JsonParser$Feature;Z)Lcom/" + "fasterxml/jackson/core/JsonFactory;"); + if (_m_JsonFactory__configure1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__configure1, f, state); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__enable1 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__enable1(jobject self_, jobject f) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__enable1, "enable", + "(Lcom/fasterxml/jackson/core/JsonParser$Feature;)Lcom/fasterxml/" + "jackson/core/JsonFactory;"); + if (_m_JsonFactory__enable1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_JsonFactory__enable1, f); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__disable1 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__disable1(jobject self_, jobject f) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__disable1, "disable", + "(Lcom/fasterxml/jackson/core/JsonParser$Feature;)Lcom/fasterxml/" + "jackson/core/JsonFactory;"); + if (_m_JsonFactory__disable1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_JsonFactory__disable1, f); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__isEnabled1 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__isEnabled1(jobject self_, jobject f) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__isEnabled1, "isEnabled", + "(Lcom/fasterxml/jackson/core/JsonParser$Feature;)Z"); + if (_m_JsonFactory__isEnabled1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod(jniEnv, self_, + _m_JsonFactory__isEnabled1, f); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonFactory__isEnabled2 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__isEnabled2(jobject self_, jobject f) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__isEnabled2, "isEnabled", + "(Lcom/fasterxml/jackson/core/StreamReadFeature;)Z"); + if (_m_JsonFactory__isEnabled2 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod(jniEnv, self_, + _m_JsonFactory__isEnabled2, f); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonFactory__getInputDecorator = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__getInputDecorator(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__getInputDecorator, + "getInputDecorator", + "()Lcom/fasterxml/jackson/core/io/InputDecorator;"); + if (_m_JsonFactory__getInputDecorator == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__getInputDecorator); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__setInputDecorator = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__setInputDecorator(jobject self_, jobject d) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__setInputDecorator, + "setInputDecorator", + "(Lcom/fasterxml/jackson/core/io/InputDecorator;)Lcom/fasterxml/" + "jackson/core/JsonFactory;"); + if (_m_JsonFactory__setInputDecorator == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__setInputDecorator, d); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__configure2 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__configure2(jobject self_, jobject f, uint8_t state) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__configure2, "configure", + "(Lcom/fasterxml/jackson/core/JsonGenerator$Feature;Z)Lcom/" + "fasterxml/jackson/core/JsonFactory;"); + if (_m_JsonFactory__configure2 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__configure2, f, state); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__enable2 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__enable2(jobject self_, jobject f) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__enable2, "enable", + "(Lcom/fasterxml/jackson/core/JsonGenerator$Feature;)Lcom/" + "fasterxml/jackson/core/JsonFactory;"); + if (_m_JsonFactory__enable2 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_JsonFactory__enable2, f); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__disable2 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__disable2(jobject self_, jobject f) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__disable2, "disable", + "(Lcom/fasterxml/jackson/core/JsonGenerator$Feature;)Lcom/" + "fasterxml/jackson/core/JsonFactory;"); + if (_m_JsonFactory__disable2 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_JsonFactory__disable2, f); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__isEnabled3 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__isEnabled3(jobject self_, jobject f) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__isEnabled3, "isEnabled", + "(Lcom/fasterxml/jackson/core/JsonGenerator$Feature;)Z"); + if (_m_JsonFactory__isEnabled3 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod(jniEnv, self_, + _m_JsonFactory__isEnabled3, f); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonFactory__isEnabled4 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__isEnabled4(jobject self_, jobject f) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__isEnabled4, "isEnabled", + "(Lcom/fasterxml/jackson/core/StreamWriteFeature;)Z"); + if (_m_JsonFactory__isEnabled4 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod(jniEnv, self_, + _m_JsonFactory__isEnabled4, f); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonFactory__getCharacterEscapes = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__getCharacterEscapes(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__getCharacterEscapes, + "getCharacterEscapes", + "()Lcom/fasterxml/jackson/core/io/CharacterEscapes;"); + if (_m_JsonFactory__getCharacterEscapes == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__getCharacterEscapes); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__setCharacterEscapes = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__setCharacterEscapes(jobject self_, jobject esc) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__setCharacterEscapes, + "setCharacterEscapes", + "(Lcom/fasterxml/jackson/core/io/CharacterEscapes;)Lcom/" + "fasterxml/jackson/core/JsonFactory;"); + if (_m_JsonFactory__setCharacterEscapes == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__setCharacterEscapes, esc); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__getOutputDecorator = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__getOutputDecorator(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__getOutputDecorator, + "getOutputDecorator", + "()Lcom/fasterxml/jackson/core/io/OutputDecorator;"); + if (_m_JsonFactory__getOutputDecorator == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__getOutputDecorator); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__setOutputDecorator = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__setOutputDecorator(jobject self_, jobject d) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__setOutputDecorator, + "setOutputDecorator", + "(Lcom/fasterxml/jackson/core/io/OutputDecorator;)Lcom/fasterxml/" + "jackson/core/JsonFactory;"); + if (_m_JsonFactory__setOutputDecorator == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__setOutputDecorator, d); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__setRootValueSeparator = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__setRootValueSeparator(jobject self_, jobject sep) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__setRootValueSeparator, + "setRootValueSeparator", + "(Ljava/lang/String;)Lcom/fasterxml/jackson/core/JsonFactory;"); + if (_m_JsonFactory__setRootValueSeparator == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__setRootValueSeparator, sep); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__getRootValueSeparator = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__getRootValueSeparator(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__getRootValueSeparator, + "getRootValueSeparator", "()Ljava/lang/String;"); + if (_m_JsonFactory__getRootValueSeparator == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__getRootValueSeparator); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__setCodec = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__setCodec(jobject self_, jobject oc) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__setCodec, "setCodec", + "(Lcom/fasterxml/jackson/core/ObjectCodec;)Lcom/fasterxml/" + "jackson/core/JsonFactory;"); + if (_m_JsonFactory__setCodec == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_JsonFactory__setCodec, oc); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__getCodec = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__getCodec(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__getCodec, "getCodec", + "()Lcom/fasterxml/jackson/core/ObjectCodec;"); + if (_m_JsonFactory__getCodec == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_JsonFactory__getCodec); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__createParser = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__createParser(jobject self_, jobject f) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__createParser, "createParser", + "(Ljava/io/File;)Lcom/fasterxml/jackson/core/JsonParser;"); + if (_m_JsonFactory__createParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__createParser, f); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__createParser1 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__createParser1(jobject self_, jobject url) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__createParser1, "createParser", + "(Ljava/net/URL;)Lcom/fasterxml/jackson/core/JsonParser;"); + if (_m_JsonFactory__createParser1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__createParser1, url); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__createParser2 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__createParser2(jobject self_, jobject in) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__createParser2, "createParser", + "(Ljava/io/InputStream;)Lcom/fasterxml/jackson/core/JsonParser;"); + if (_m_JsonFactory__createParser2 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__createParser2, in); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__createParser3 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__createParser3(jobject self_, jobject r) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__createParser3, "createParser", + "(Ljava/io/Reader;)Lcom/fasterxml/jackson/core/JsonParser;"); + if (_m_JsonFactory__createParser3 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__createParser3, r); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__createParser4 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__createParser4(jobject self_, jobject data) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__createParser4, "createParser", + "([B)Lcom/fasterxml/jackson/core/JsonParser;"); + if (_m_JsonFactory__createParser4 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__createParser4, data); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__createParser5 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__createParser5(jobject self_, + jobject data, + int32_t offset, + int32_t len) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__createParser5, "createParser", + "([BII)Lcom/fasterxml/jackson/core/JsonParser;"); + if (_m_JsonFactory__createParser5 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__createParser5, data, offset, len); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__createParser6 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__createParser6(jobject self_, jobject content) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__createParser6, "createParser", + "(Ljava/lang/String;)Lcom/fasterxml/jackson/core/JsonParser;"); + if (_m_JsonFactory__createParser6 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__createParser6, content); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__createParser7 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__createParser7(jobject self_, jobject content) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__createParser7, "createParser", + "([C)Lcom/fasterxml/jackson/core/JsonParser;"); + if (_m_JsonFactory__createParser7 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__createParser7, content); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__createParser8 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__createParser8(jobject self_, + jobject content, + int32_t offset, + int32_t len) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__createParser8, "createParser", + "([CII)Lcom/fasterxml/jackson/core/JsonParser;"); + if (_m_JsonFactory__createParser8 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__createParser8, content, offset, len); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__createParser9 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__createParser9(jobject self_, jobject in) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__createParser9, "createParser", + "(Ljava/io/DataInput;)Lcom/fasterxml/jackson/core/JsonParser;"); + if (_m_JsonFactory__createParser9 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__createParser9, in); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__createNonBlockingByteArrayParser = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__createNonBlockingByteArrayParser(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__createNonBlockingByteArrayParser, + "createNonBlockingByteArrayParser", + "()Lcom/fasterxml/jackson/core/JsonParser;"); + if (_m_JsonFactory__createNonBlockingByteArrayParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__createNonBlockingByteArrayParser); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__createGenerator = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__createGenerator(jobject self_, + jobject out, + jobject enc) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__createGenerator, + "createGenerator", + "(Ljava/io/OutputStream;Lcom/fasterxml/jackson/core/" + "JsonEncoding;)Lcom/fasterxml/jackson/core/JsonGenerator;"); + if (_m_JsonFactory__createGenerator == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__createGenerator, out, enc); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__createGenerator1 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__createGenerator1(jobject self_, jobject out) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method( + _c_JsonFactory, &_m_JsonFactory__createGenerator1, "createGenerator", + "(Ljava/io/OutputStream;)Lcom/fasterxml/jackson/core/JsonGenerator;"); + if (_m_JsonFactory__createGenerator1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__createGenerator1, out); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__createGenerator2 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__createGenerator2(jobject self_, jobject w) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__createGenerator2, + "createGenerator", + "(Ljava/io/Writer;)Lcom/fasterxml/jackson/core/JsonGenerator;"); + if (_m_JsonFactory__createGenerator2 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__createGenerator2, w); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__createGenerator3 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__createGenerator3(jobject self_, jobject f, jobject enc) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__createGenerator3, + "createGenerator", + "(Ljava/io/File;Lcom/fasterxml/jackson/core/JsonEncoding;)Lcom/" + "fasterxml/jackson/core/JsonGenerator;"); + if (_m_JsonFactory__createGenerator3 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__createGenerator3, f, enc); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__createGenerator4 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__createGenerator4(jobject self_, + jobject out, + jobject enc) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__createGenerator4, + "createGenerator", + "(Ljava/io/DataOutput;Lcom/fasterxml/jackson/core/" + "JsonEncoding;)Lcom/fasterxml/jackson/core/JsonGenerator;"); + if (_m_JsonFactory__createGenerator4 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__createGenerator4, out, enc); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__createGenerator5 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__createGenerator5(jobject self_, jobject out) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method( + _c_JsonFactory, &_m_JsonFactory__createGenerator5, "createGenerator", + "(Ljava/io/DataOutput;)Lcom/fasterxml/jackson/core/JsonGenerator;"); + if (_m_JsonFactory__createGenerator5 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__createGenerator5, out); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__createJsonParser = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__createJsonParser(jobject self_, jobject f) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__createJsonParser, + "createJsonParser", + "(Ljava/io/File;)Lcom/fasterxml/jackson/core/JsonParser;"); + if (_m_JsonFactory__createJsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__createJsonParser, f); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__createJsonParser1 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__createJsonParser1(jobject self_, jobject url) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__createJsonParser1, + "createJsonParser", + "(Ljava/net/URL;)Lcom/fasterxml/jackson/core/JsonParser;"); + if (_m_JsonFactory__createJsonParser1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__createJsonParser1, url); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__createJsonParser2 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__createJsonParser2(jobject self_, jobject in) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__createJsonParser2, + "createJsonParser", + "(Ljava/io/InputStream;)Lcom/fasterxml/jackson/core/JsonParser;"); + if (_m_JsonFactory__createJsonParser2 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__createJsonParser2, in); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__createJsonParser3 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__createJsonParser3(jobject self_, jobject r) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__createJsonParser3, + "createJsonParser", + "(Ljava/io/Reader;)Lcom/fasterxml/jackson/core/JsonParser;"); + if (_m_JsonFactory__createJsonParser3 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__createJsonParser3, r); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__createJsonParser4 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__createJsonParser4(jobject self_, jobject data) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__createJsonParser4, + "createJsonParser", + "([B)Lcom/fasterxml/jackson/core/JsonParser;"); + if (_m_JsonFactory__createJsonParser4 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__createJsonParser4, data); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__createJsonParser5 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__createJsonParser5(jobject self_, + jobject data, + int32_t offset, + int32_t len) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__createJsonParser5, + "createJsonParser", + "([BII)Lcom/fasterxml/jackson/core/JsonParser;"); + if (_m_JsonFactory__createJsonParser5 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__createJsonParser5, data, offset, len); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__createJsonParser6 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__createJsonParser6(jobject self_, jobject content) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__createJsonParser6, + "createJsonParser", + "(Ljava/lang/String;)Lcom/fasterxml/jackson/core/JsonParser;"); + if (_m_JsonFactory__createJsonParser6 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__createJsonParser6, content); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__createJsonGenerator = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__createJsonGenerator(jobject self_, + jobject out, + jobject enc) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__createJsonGenerator, + "createJsonGenerator", + "(Ljava/io/OutputStream;Lcom/fasterxml/jackson/core/" + "JsonEncoding;)Lcom/fasterxml/jackson/core/JsonGenerator;"); + if (_m_JsonFactory__createJsonGenerator == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__createJsonGenerator, out, enc); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__createJsonGenerator1 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__createJsonGenerator1(jobject self_, jobject out) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory, &_m_JsonFactory__createJsonGenerator1, + "createJsonGenerator", + "(Ljava/io/Writer;)Lcom/fasterxml/jackson/core/JsonGenerator;"); + if (_m_JsonFactory__createJsonGenerator1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__createJsonGenerator1, out); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory__createJsonGenerator2 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory__createJsonGenerator2(jobject self_, jobject out) { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method( + _c_JsonFactory, &_m_JsonFactory__createJsonGenerator2, + "createJsonGenerator", + "(Ljava/io/OutputStream;)Lcom/fasterxml/jackson/core/JsonGenerator;"); + if (_m_JsonFactory__createJsonGenerator2 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonFactory__createJsonGenerator2, out); + return to_global_ref_result(_result); +} + +jfieldID _f_JsonFactory__DEFAULT_FACTORY_FEATURE_FLAGS = NULL; +FFI_PLUGIN_EXPORT +JniResult get_JsonFactory__DEFAULT_FACTORY_FEATURE_FLAGS() { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_JsonFactory, + &_f_JsonFactory__DEFAULT_FACTORY_FEATURE_FLAGS, + "DEFAULT_FACTORY_FEATURE_FLAGS", "I"); + int32_t _result = (*jniEnv)->GetStaticIntField( + jniEnv, _c_JsonFactory, _f_JsonFactory__DEFAULT_FACTORY_FEATURE_FLAGS); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jfieldID _f_JsonFactory__DEFAULT_PARSER_FEATURE_FLAGS = NULL; +FFI_PLUGIN_EXPORT +JniResult get_JsonFactory__DEFAULT_PARSER_FEATURE_FLAGS() { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_JsonFactory, + &_f_JsonFactory__DEFAULT_PARSER_FEATURE_FLAGS, + "DEFAULT_PARSER_FEATURE_FLAGS", "I"); + int32_t _result = (*jniEnv)->GetStaticIntField( + jniEnv, _c_JsonFactory, _f_JsonFactory__DEFAULT_PARSER_FEATURE_FLAGS); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jfieldID _f_JsonFactory__DEFAULT_GENERATOR_FEATURE_FLAGS = NULL; +FFI_PLUGIN_EXPORT +JniResult get_JsonFactory__DEFAULT_GENERATOR_FEATURE_FLAGS() { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_JsonFactory, + &_f_JsonFactory__DEFAULT_GENERATOR_FEATURE_FLAGS, + "DEFAULT_GENERATOR_FEATURE_FLAGS", "I"); + int32_t _result = (*jniEnv)->GetStaticIntField( + jniEnv, _c_JsonFactory, _f_JsonFactory__DEFAULT_GENERATOR_FEATURE_FLAGS); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jfieldID _f_JsonFactory__DEFAULT_ROOT_VALUE_SEPARATOR = NULL; +FFI_PLUGIN_EXPORT +JniResult get_JsonFactory__DEFAULT_ROOT_VALUE_SEPARATOR() { + load_env(); + load_class_global_ref(&_c_JsonFactory, + "com/fasterxml/jackson/core/JsonFactory"); + if (_c_JsonFactory == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_JsonFactory, + &_f_JsonFactory__DEFAULT_ROOT_VALUE_SEPARATOR, + "DEFAULT_ROOT_VALUE_SEPARATOR", + "Lcom/fasterxml/jackson/core/SerializableString;"); + jobject _result = (*jniEnv)->GetStaticObjectField( + jniEnv, _c_JsonFactory, _f_JsonFactory__DEFAULT_ROOT_VALUE_SEPARATOR); + return to_global_ref_result(_result); +} + +// com.fasterxml.jackson.core.JsonFactory$Feature +jclass _c_JsonFactory_Feature = NULL; + +jmethodID _m_JsonFactory_Feature__values = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory_Feature__values() { + load_env(); + load_class_global_ref(&_c_JsonFactory_Feature, + "com/fasterxml/jackson/core/JsonFactory$Feature"); + if (_c_JsonFactory_Feature == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_JsonFactory_Feature, &_m_JsonFactory_Feature__values, + "values", + "()[Lcom/fasterxml/jackson/core/JsonFactory$Feature;"); + if (_m_JsonFactory_Feature__values == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_JsonFactory_Feature, _m_JsonFactory_Feature__values); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory_Feature__valueOf = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory_Feature__valueOf(jobject name) { + load_env(); + load_class_global_ref(&_c_JsonFactory_Feature, + "com/fasterxml/jackson/core/JsonFactory$Feature"); + if (_c_JsonFactory_Feature == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method( + _c_JsonFactory_Feature, &_m_JsonFactory_Feature__valueOf, "valueOf", + "(Ljava/lang/String;)Lcom/fasterxml/jackson/core/JsonFactory$Feature;"); + if (_m_JsonFactory_Feature__valueOf == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_JsonFactory_Feature, _m_JsonFactory_Feature__valueOf, name); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonFactory_Feature__collectDefaults = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory_Feature__collectDefaults() { + load_env(); + load_class_global_ref(&_c_JsonFactory_Feature, + "com/fasterxml/jackson/core/JsonFactory$Feature"); + if (_c_JsonFactory_Feature == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_JsonFactory_Feature, + &_m_JsonFactory_Feature__collectDefaults, + "collectDefaults", "()I"); + if (_m_JsonFactory_Feature__collectDefaults == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = (*jniEnv)->CallStaticIntMethod( + jniEnv, _c_JsonFactory_Feature, _m_JsonFactory_Feature__collectDefaults); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonFactory_Feature__enabledByDefault = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory_Feature__enabledByDefault(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonFactory_Feature, + "com/fasterxml/jackson/core/JsonFactory$Feature"); + if (_c_JsonFactory_Feature == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory_Feature, &_m_JsonFactory_Feature__enabledByDefault, + "enabledByDefault", "()Z"); + if (_m_JsonFactory_Feature__enabledByDefault == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod( + jniEnv, self_, _m_JsonFactory_Feature__enabledByDefault); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonFactory_Feature__enabledIn = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory_Feature__enabledIn(jobject self_, int32_t flags) { + load_env(); + load_class_global_ref(&_c_JsonFactory_Feature, + "com/fasterxml/jackson/core/JsonFactory$Feature"); + if (_c_JsonFactory_Feature == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory_Feature, &_m_JsonFactory_Feature__enabledIn, + "enabledIn", "(I)Z"); + if (_m_JsonFactory_Feature__enabledIn == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod( + jniEnv, self_, _m_JsonFactory_Feature__enabledIn, flags); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonFactory_Feature__getMask = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonFactory_Feature__getMask(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonFactory_Feature, + "com/fasterxml/jackson/core/JsonFactory$Feature"); + if (_c_JsonFactory_Feature == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonFactory_Feature, &_m_JsonFactory_Feature__getMask, + "getMask", "()I"); + if (_m_JsonFactory_Feature__getMask == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = + (*jniEnv)->CallIntMethod(jniEnv, self_, _m_JsonFactory_Feature__getMask); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +// com.fasterxml.jackson.core.JsonParser +jclass _c_JsonParser = NULL; + +jmethodID _m_JsonParser__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__new0() { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__new0, "", "()V"); + if (_m_JsonParser__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->NewObject(jniEnv, _c_JsonParser, _m_JsonParser__new0); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__new1 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__new1(int32_t features) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__new1, "", "(I)V"); + if (_m_JsonParser__new1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject(jniEnv, _c_JsonParser, + _m_JsonParser__new1, features); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__getCodec = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getCodec(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getCodec, "getCodec", + "()Lcom/fasterxml/jackson/core/ObjectCodec;"); + if (_m_JsonParser__getCodec == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_JsonParser__getCodec); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__setCodec = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__setCodec(jobject self_, jobject oc) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__setCodec, "setCodec", + "(Lcom/fasterxml/jackson/core/ObjectCodec;)V"); + if (_m_JsonParser__setCodec == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_JsonParser__setCodec, oc); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__getInputSource = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getInputSource(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getInputSource, "getInputSource", + "()Ljava/lang/Object;"); + if (_m_JsonParser__getInputSource == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_JsonParser__getInputSource); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__setRequestPayloadOnError = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__setRequestPayloadOnError(jobject self_, jobject payload) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__setRequestPayloadOnError, + "setRequestPayloadOnError", + "(Lcom/fasterxml/jackson/core/util/RequestPayload;)V"); + if (_m_JsonParser__setRequestPayloadOnError == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, + _m_JsonParser__setRequestPayloadOnError, payload); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__setRequestPayloadOnError1 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__setRequestPayloadOnError1(jobject self_, + jobject payload, + jobject charset) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__setRequestPayloadOnError1, + "setRequestPayloadOnError", "([BLjava/lang/String;)V"); + if (_m_JsonParser__setRequestPayloadOnError1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, + _m_JsonParser__setRequestPayloadOnError1, payload, + charset); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__setRequestPayloadOnError2 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__setRequestPayloadOnError2(jobject self_, + jobject payload) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__setRequestPayloadOnError2, + "setRequestPayloadOnError", "(Ljava/lang/String;)V"); + if (_m_JsonParser__setRequestPayloadOnError2 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, + _m_JsonParser__setRequestPayloadOnError2, payload); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__setSchema = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__setSchema(jobject self_, jobject schema) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__setSchema, "setSchema", + "(Lcom/fasterxml/jackson/core/FormatSchema;)V"); + if (_m_JsonParser__setSchema == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_JsonParser__setSchema, schema); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__getSchema = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getSchema(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getSchema, "getSchema", + "()Lcom/fasterxml/jackson/core/FormatSchema;"); + if (_m_JsonParser__getSchema == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_JsonParser__getSchema); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__canUseSchema = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__canUseSchema(jobject self_, jobject schema) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__canUseSchema, "canUseSchema", + "(Lcom/fasterxml/jackson/core/FormatSchema;)Z"); + if (_m_JsonParser__canUseSchema == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod( + jniEnv, self_, _m_JsonParser__canUseSchema, schema); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__requiresCustomCodec = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__requiresCustomCodec(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__requiresCustomCodec, + "requiresCustomCodec", "()Z"); + if (_m_JsonParser__requiresCustomCodec == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod( + jniEnv, self_, _m_JsonParser__requiresCustomCodec); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__canParseAsync = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__canParseAsync(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__canParseAsync, "canParseAsync", + "()Z"); + if (_m_JsonParser__canParseAsync == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = + (*jniEnv)->CallBooleanMethod(jniEnv, self_, _m_JsonParser__canParseAsync); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__getNonBlockingInputFeeder = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getNonBlockingInputFeeder(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getNonBlockingInputFeeder, + "getNonBlockingInputFeeder", + "()Lcom/fasterxml/jackson/core/async/NonBlockingInputFeeder;"); + if (_m_JsonParser__getNonBlockingInputFeeder == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonParser__getNonBlockingInputFeeder); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__getReadCapabilities = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getReadCapabilities(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getReadCapabilities, + "getReadCapabilities", + "()Lcom/fasterxml/jackson/core/util/JacksonFeatureSet;"); + if (_m_JsonParser__getReadCapabilities == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonParser__getReadCapabilities); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__version = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__version(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__version, "version", + "()Lcom/fasterxml/jackson/core/Version;"); + if (_m_JsonParser__version == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_JsonParser__version); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__close = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__close(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__close, "close", "()V"); + if (_m_JsonParser__close == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_JsonParser__close); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__isClosed = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__isClosed(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__isClosed, "isClosed", "()Z"); + if (_m_JsonParser__isClosed == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = + (*jniEnv)->CallBooleanMethod(jniEnv, self_, _m_JsonParser__isClosed); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__getParsingContext = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getParsingContext(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getParsingContext, + "getParsingContext", + "()Lcom/fasterxml/jackson/core/JsonStreamContext;"); + if (_m_JsonParser__getParsingContext == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonParser__getParsingContext); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__currentLocation = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__currentLocation(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__currentLocation, "currentLocation", + "()Lcom/fasterxml/jackson/core/JsonLocation;"); + if (_m_JsonParser__currentLocation == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod(jniEnv, self_, + _m_JsonParser__currentLocation); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__currentTokenLocation = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__currentTokenLocation(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__currentTokenLocation, + "currentTokenLocation", + "()Lcom/fasterxml/jackson/core/JsonLocation;"); + if (_m_JsonParser__currentTokenLocation == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonParser__currentTokenLocation); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__getCurrentLocation = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getCurrentLocation(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getCurrentLocation, + "getCurrentLocation", + "()Lcom/fasterxml/jackson/core/JsonLocation;"); + if (_m_JsonParser__getCurrentLocation == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonParser__getCurrentLocation); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__getTokenLocation = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getTokenLocation(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getTokenLocation, + "getTokenLocation", + "()Lcom/fasterxml/jackson/core/JsonLocation;"); + if (_m_JsonParser__getTokenLocation == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonParser__getTokenLocation); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__currentValue = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__currentValue(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__currentValue, "currentValue", + "()Ljava/lang/Object;"); + if (_m_JsonParser__currentValue == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_JsonParser__currentValue); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__assignCurrentValue = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__assignCurrentValue(jobject self_, jobject v) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__assignCurrentValue, + "assignCurrentValue", "(Ljava/lang/Object;)V"); + if (_m_JsonParser__assignCurrentValue == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_JsonParser__assignCurrentValue, + v); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__getCurrentValue = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getCurrentValue(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getCurrentValue, "getCurrentValue", + "()Ljava/lang/Object;"); + if (_m_JsonParser__getCurrentValue == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod(jniEnv, self_, + _m_JsonParser__getCurrentValue); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__setCurrentValue = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__setCurrentValue(jobject self_, jobject v) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__setCurrentValue, "setCurrentValue", + "(Ljava/lang/Object;)V"); + if (_m_JsonParser__setCurrentValue == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_JsonParser__setCurrentValue, v); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__releaseBuffered = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__releaseBuffered(jobject self_, jobject out) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__releaseBuffered, "releaseBuffered", + "(Ljava/io/OutputStream;)I"); + if (_m_JsonParser__releaseBuffered == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = (*jniEnv)->CallIntMethod( + jniEnv, self_, _m_JsonParser__releaseBuffered, out); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__releaseBuffered1 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__releaseBuffered1(jobject self_, jobject w) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__releaseBuffered1, + "releaseBuffered", "(Ljava/io/Writer;)I"); + if (_m_JsonParser__releaseBuffered1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = (*jniEnv)->CallIntMethod( + jniEnv, self_, _m_JsonParser__releaseBuffered1, w); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__enable = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__enable(jobject self_, jobject f) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__enable, "enable", + "(Lcom/fasterxml/jackson/core/JsonParser$Feature;)Lcom/fasterxml/" + "jackson/core/JsonParser;"); + if (_m_JsonParser__enable == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_JsonParser__enable, f); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__disable = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__disable(jobject self_, jobject f) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__disable, "disable", + "(Lcom/fasterxml/jackson/core/JsonParser$Feature;)Lcom/fasterxml/" + "jackson/core/JsonParser;"); + if (_m_JsonParser__disable == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_JsonParser__disable, f); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__configure = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__configure(jobject self_, jobject f, uint8_t state) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__configure, "configure", + "(Lcom/fasterxml/jackson/core/JsonParser$Feature;Z)Lcom/" + "fasterxml/jackson/core/JsonParser;"); + if (_m_JsonParser__configure == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonParser__configure, f, state); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__isEnabled = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__isEnabled(jobject self_, jobject f) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__isEnabled, "isEnabled", + "(Lcom/fasterxml/jackson/core/JsonParser$Feature;)Z"); + if (_m_JsonParser__isEnabled == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = + (*jniEnv)->CallBooleanMethod(jniEnv, self_, _m_JsonParser__isEnabled, f); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__isEnabled1 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__isEnabled1(jobject self_, jobject f) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__isEnabled1, "isEnabled", + "(Lcom/fasterxml/jackson/core/StreamReadFeature;)Z"); + if (_m_JsonParser__isEnabled1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = + (*jniEnv)->CallBooleanMethod(jniEnv, self_, _m_JsonParser__isEnabled1, f); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__getFeatureMask = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getFeatureMask(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getFeatureMask, "getFeatureMask", + "()I"); + if (_m_JsonParser__getFeatureMask == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = + (*jniEnv)->CallIntMethod(jniEnv, self_, _m_JsonParser__getFeatureMask); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__setFeatureMask = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__setFeatureMask(jobject self_, int32_t mask) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__setFeatureMask, "setFeatureMask", + "(I)Lcom/fasterxml/jackson/core/JsonParser;"); + if (_m_JsonParser__setFeatureMask == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonParser__setFeatureMask, mask); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__overrideStdFeatures = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__overrideStdFeatures(jobject self_, + int32_t values, + int32_t mask) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__overrideStdFeatures, + "overrideStdFeatures", + "(II)Lcom/fasterxml/jackson/core/JsonParser;"); + if (_m_JsonParser__overrideStdFeatures == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonParser__overrideStdFeatures, values, mask); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__getFormatFeatures = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getFormatFeatures(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getFormatFeatures, + "getFormatFeatures", "()I"); + if (_m_JsonParser__getFormatFeatures == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = + (*jniEnv)->CallIntMethod(jniEnv, self_, _m_JsonParser__getFormatFeatures); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__overrideFormatFeatures = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__overrideFormatFeatures(jobject self_, + int32_t values, + int32_t mask) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__overrideFormatFeatures, + "overrideFormatFeatures", + "(II)Lcom/fasterxml/jackson/core/JsonParser;"); + if (_m_JsonParser__overrideFormatFeatures == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonParser__overrideFormatFeatures, values, mask); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__nextToken = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__nextToken(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__nextToken, "nextToken", + "()Lcom/fasterxml/jackson/core/JsonToken;"); + if (_m_JsonParser__nextToken == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_JsonParser__nextToken); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__nextValue = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__nextValue(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__nextValue, "nextValue", + "()Lcom/fasterxml/jackson/core/JsonToken;"); + if (_m_JsonParser__nextValue == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_JsonParser__nextValue); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__nextFieldName = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__nextFieldName(jobject self_, jobject str) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__nextFieldName, "nextFieldName", + "(Lcom/fasterxml/jackson/core/SerializableString;)Z"); + if (_m_JsonParser__nextFieldName == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod( + jniEnv, self_, _m_JsonParser__nextFieldName, str); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__nextFieldName1 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__nextFieldName1(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__nextFieldName1, "nextFieldName", + "()Ljava/lang/String;"); + if (_m_JsonParser__nextFieldName1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_JsonParser__nextFieldName1); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__nextTextValue = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__nextTextValue(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__nextTextValue, "nextTextValue", + "()Ljava/lang/String;"); + if (_m_JsonParser__nextTextValue == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_JsonParser__nextTextValue); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__nextIntValue = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__nextIntValue(jobject self_, int32_t defaultValue) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__nextIntValue, "nextIntValue", + "(I)I"); + if (_m_JsonParser__nextIntValue == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = (*jniEnv)->CallIntMethod( + jniEnv, self_, _m_JsonParser__nextIntValue, defaultValue); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__nextLongValue = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__nextLongValue(jobject self_, int64_t defaultValue) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__nextLongValue, "nextLongValue", + "(J)J"); + if (_m_JsonParser__nextLongValue == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int64_t _result = (*jniEnv)->CallLongMethod( + jniEnv, self_, _m_JsonParser__nextLongValue, defaultValue); + return (JniResult){.value = {.j = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__nextBooleanValue = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__nextBooleanValue(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__nextBooleanValue, + "nextBooleanValue", "()Ljava/lang/Boolean;"); + if (_m_JsonParser__nextBooleanValue == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonParser__nextBooleanValue); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__skipChildren = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__skipChildren(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__skipChildren, "skipChildren", + "()Lcom/fasterxml/jackson/core/JsonParser;"); + if (_m_JsonParser__skipChildren == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_JsonParser__skipChildren); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__finishToken = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__finishToken(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__finishToken, "finishToken", "()V"); + if (_m_JsonParser__finishToken == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_JsonParser__finishToken); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__currentToken = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__currentToken(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__currentToken, "currentToken", + "()Lcom/fasterxml/jackson/core/JsonToken;"); + if (_m_JsonParser__currentToken == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_JsonParser__currentToken); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__currentTokenId = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__currentTokenId(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__currentTokenId, "currentTokenId", + "()I"); + if (_m_JsonParser__currentTokenId == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = + (*jniEnv)->CallIntMethod(jniEnv, self_, _m_JsonParser__currentTokenId); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__getCurrentToken = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getCurrentToken(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getCurrentToken, "getCurrentToken", + "()Lcom/fasterxml/jackson/core/JsonToken;"); + if (_m_JsonParser__getCurrentToken == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod(jniEnv, self_, + _m_JsonParser__getCurrentToken); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__getCurrentTokenId = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getCurrentTokenId(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getCurrentTokenId, + "getCurrentTokenId", "()I"); + if (_m_JsonParser__getCurrentTokenId == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = + (*jniEnv)->CallIntMethod(jniEnv, self_, _m_JsonParser__getCurrentTokenId); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__hasCurrentToken = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__hasCurrentToken(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__hasCurrentToken, "hasCurrentToken", + "()Z"); + if (_m_JsonParser__hasCurrentToken == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod( + jniEnv, self_, _m_JsonParser__hasCurrentToken); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__hasTokenId = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__hasTokenId(jobject self_, int32_t id) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__hasTokenId, "hasTokenId", "(I)Z"); + if (_m_JsonParser__hasTokenId == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod(jniEnv, self_, + _m_JsonParser__hasTokenId, id); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__hasToken = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__hasToken(jobject self_, jobject t) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__hasToken, "hasToken", + "(Lcom/fasterxml/jackson/core/JsonToken;)Z"); + if (_m_JsonParser__hasToken == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = + (*jniEnv)->CallBooleanMethod(jniEnv, self_, _m_JsonParser__hasToken, t); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__isExpectedStartArrayToken = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__isExpectedStartArrayToken(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__isExpectedStartArrayToken, + "isExpectedStartArrayToken", "()Z"); + if (_m_JsonParser__isExpectedStartArrayToken == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod( + jniEnv, self_, _m_JsonParser__isExpectedStartArrayToken); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__isExpectedStartObjectToken = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__isExpectedStartObjectToken(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__isExpectedStartObjectToken, + "isExpectedStartObjectToken", "()Z"); + if (_m_JsonParser__isExpectedStartObjectToken == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod( + jniEnv, self_, _m_JsonParser__isExpectedStartObjectToken); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__isExpectedNumberIntToken = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__isExpectedNumberIntToken(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__isExpectedNumberIntToken, + "isExpectedNumberIntToken", "()Z"); + if (_m_JsonParser__isExpectedNumberIntToken == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod( + jniEnv, self_, _m_JsonParser__isExpectedNumberIntToken); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__isNaN = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__isNaN(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__isNaN, "isNaN", "()Z"); + if (_m_JsonParser__isNaN == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = + (*jniEnv)->CallBooleanMethod(jniEnv, self_, _m_JsonParser__isNaN); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__clearCurrentToken = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__clearCurrentToken(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__clearCurrentToken, + "clearCurrentToken", "()V"); + if (_m_JsonParser__clearCurrentToken == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_JsonParser__clearCurrentToken); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__getLastClearedToken = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getLastClearedToken(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getLastClearedToken, + "getLastClearedToken", + "()Lcom/fasterxml/jackson/core/JsonToken;"); + if (_m_JsonParser__getLastClearedToken == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonParser__getLastClearedToken); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__overrideCurrentName = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__overrideCurrentName(jobject self_, jobject name) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__overrideCurrentName, + "overrideCurrentName", "(Ljava/lang/String;)V"); + if (_m_JsonParser__overrideCurrentName == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_JsonParser__overrideCurrentName, + name); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__getCurrentName = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getCurrentName(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getCurrentName, "getCurrentName", + "()Ljava/lang/String;"); + if (_m_JsonParser__getCurrentName == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_JsonParser__getCurrentName); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__currentName = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__currentName(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__currentName, "currentName", + "()Ljava/lang/String;"); + if (_m_JsonParser__currentName == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_JsonParser__currentName); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__getText = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getText(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getText, "getText", + "()Ljava/lang/String;"); + if (_m_JsonParser__getText == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_JsonParser__getText); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__getText1 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getText1(jobject self_, jobject writer) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getText1, "getText", + "(Ljava/io/Writer;)I"); + if (_m_JsonParser__getText1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = + (*jniEnv)->CallIntMethod(jniEnv, self_, _m_JsonParser__getText1, writer); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__getTextCharacters = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getTextCharacters(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getTextCharacters, + "getTextCharacters", "()[C"); + if (_m_JsonParser__getTextCharacters == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonParser__getTextCharacters); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__getTextLength = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getTextLength(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getTextLength, "getTextLength", + "()I"); + if (_m_JsonParser__getTextLength == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = + (*jniEnv)->CallIntMethod(jniEnv, self_, _m_JsonParser__getTextLength); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__getTextOffset = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getTextOffset(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getTextOffset, "getTextOffset", + "()I"); + if (_m_JsonParser__getTextOffset == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = + (*jniEnv)->CallIntMethod(jniEnv, self_, _m_JsonParser__getTextOffset); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__hasTextCharacters = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__hasTextCharacters(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__hasTextCharacters, + "hasTextCharacters", "()Z"); + if (_m_JsonParser__hasTextCharacters == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod( + jniEnv, self_, _m_JsonParser__hasTextCharacters); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__getNumberValue = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getNumberValue(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getNumberValue, "getNumberValue", + "()Ljava/lang/Number;"); + if (_m_JsonParser__getNumberValue == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_JsonParser__getNumberValue); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__getNumberValueExact = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getNumberValueExact(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getNumberValueExact, + "getNumberValueExact", "()Ljava/lang/Number;"); + if (_m_JsonParser__getNumberValueExact == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonParser__getNumberValueExact); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__getNumberType = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getNumberType(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getNumberType, "getNumberType", + "()Lcom/fasterxml/jackson/core/JsonParser$NumberType;"); + if (_m_JsonParser__getNumberType == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_JsonParser__getNumberType); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__getByteValue = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getByteValue(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getByteValue, "getByteValue", + "()B"); + if (_m_JsonParser__getByteValue == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int8_t _result = + (*jniEnv)->CallByteMethod(jniEnv, self_, _m_JsonParser__getByteValue); + return (JniResult){.value = {.b = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__getShortValue = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getShortValue(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getShortValue, "getShortValue", + "()S"); + if (_m_JsonParser__getShortValue == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int16_t _result = + (*jniEnv)->CallShortMethod(jniEnv, self_, _m_JsonParser__getShortValue); + return (JniResult){.value = {.s = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__getIntValue = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getIntValue(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getIntValue, "getIntValue", "()I"); + if (_m_JsonParser__getIntValue == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = + (*jniEnv)->CallIntMethod(jniEnv, self_, _m_JsonParser__getIntValue); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__getLongValue = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getLongValue(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getLongValue, "getLongValue", + "()J"); + if (_m_JsonParser__getLongValue == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int64_t _result = + (*jniEnv)->CallLongMethod(jniEnv, self_, _m_JsonParser__getLongValue); + return (JniResult){.value = {.j = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__getBigIntegerValue = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getBigIntegerValue(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getBigIntegerValue, + "getBigIntegerValue", "()Ljava/math/BigInteger;"); + if (_m_JsonParser__getBigIntegerValue == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonParser__getBigIntegerValue); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__getFloatValue = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getFloatValue(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getFloatValue, "getFloatValue", + "()F"); + if (_m_JsonParser__getFloatValue == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + float _result = + (*jniEnv)->CallFloatMethod(jniEnv, self_, _m_JsonParser__getFloatValue); + return (JniResult){.value = {.f = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__getDoubleValue = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getDoubleValue(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getDoubleValue, "getDoubleValue", + "()D"); + if (_m_JsonParser__getDoubleValue == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + double _result = + (*jniEnv)->CallDoubleMethod(jniEnv, self_, _m_JsonParser__getDoubleValue); + return (JniResult){.value = {.d = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__getDecimalValue = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getDecimalValue(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getDecimalValue, "getDecimalValue", + "()Ljava/math/BigDecimal;"); + if (_m_JsonParser__getDecimalValue == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod(jniEnv, self_, + _m_JsonParser__getDecimalValue); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__getBooleanValue = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getBooleanValue(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getBooleanValue, "getBooleanValue", + "()Z"); + if (_m_JsonParser__getBooleanValue == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod( + jniEnv, self_, _m_JsonParser__getBooleanValue); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__getEmbeddedObject = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getEmbeddedObject(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getEmbeddedObject, + "getEmbeddedObject", "()Ljava/lang/Object;"); + if (_m_JsonParser__getEmbeddedObject == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonParser__getEmbeddedObject); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__getBinaryValue = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getBinaryValue(jobject self_, jobject bv) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getBinaryValue, "getBinaryValue", + "(Lcom/fasterxml/jackson/core/Base64Variant;)[B"); + if (_m_JsonParser__getBinaryValue == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonParser__getBinaryValue, bv); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__getBinaryValue1 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getBinaryValue1(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getBinaryValue1, "getBinaryValue", + "()[B"); + if (_m_JsonParser__getBinaryValue1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod(jniEnv, self_, + _m_JsonParser__getBinaryValue1); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__readBinaryValue = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__readBinaryValue(jobject self_, jobject out) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__readBinaryValue, "readBinaryValue", + "(Ljava/io/OutputStream;)I"); + if (_m_JsonParser__readBinaryValue == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = (*jniEnv)->CallIntMethod( + jniEnv, self_, _m_JsonParser__readBinaryValue, out); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__readBinaryValue1 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__readBinaryValue1(jobject self_, jobject bv, jobject out) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method( + _c_JsonParser, &_m_JsonParser__readBinaryValue1, "readBinaryValue", + "(Lcom/fasterxml/jackson/core/Base64Variant;Ljava/io/OutputStream;)I"); + if (_m_JsonParser__readBinaryValue1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = (*jniEnv)->CallIntMethod( + jniEnv, self_, _m_JsonParser__readBinaryValue1, bv, out); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__getValueAsInt = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getValueAsInt(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getValueAsInt, "getValueAsInt", + "()I"); + if (_m_JsonParser__getValueAsInt == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = + (*jniEnv)->CallIntMethod(jniEnv, self_, _m_JsonParser__getValueAsInt); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__getValueAsInt1 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getValueAsInt1(jobject self_, int32_t def) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getValueAsInt1, "getValueAsInt", + "(I)I"); + if (_m_JsonParser__getValueAsInt1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = (*jniEnv)->CallIntMethod( + jniEnv, self_, _m_JsonParser__getValueAsInt1, def); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__getValueAsLong = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getValueAsLong(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getValueAsLong, "getValueAsLong", + "()J"); + if (_m_JsonParser__getValueAsLong == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int64_t _result = + (*jniEnv)->CallLongMethod(jniEnv, self_, _m_JsonParser__getValueAsLong); + return (JniResult){.value = {.j = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__getValueAsLong1 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getValueAsLong1(jobject self_, int64_t def) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getValueAsLong1, "getValueAsLong", + "(J)J"); + if (_m_JsonParser__getValueAsLong1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int64_t _result = (*jniEnv)->CallLongMethod( + jniEnv, self_, _m_JsonParser__getValueAsLong1, def); + return (JniResult){.value = {.j = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__getValueAsDouble = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getValueAsDouble(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getValueAsDouble, + "getValueAsDouble", "()D"); + if (_m_JsonParser__getValueAsDouble == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + double _result = (*jniEnv)->CallDoubleMethod(jniEnv, self_, + _m_JsonParser__getValueAsDouble); + return (JniResult){.value = {.d = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__getValueAsDouble1 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getValueAsDouble1(jobject self_, double def) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getValueAsDouble1, + "getValueAsDouble", "(D)D"); + if (_m_JsonParser__getValueAsDouble1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + double _result = (*jniEnv)->CallDoubleMethod( + jniEnv, self_, _m_JsonParser__getValueAsDouble1, def); + return (JniResult){.value = {.d = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__getValueAsBoolean = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getValueAsBoolean(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getValueAsBoolean, + "getValueAsBoolean", "()Z"); + if (_m_JsonParser__getValueAsBoolean == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod( + jniEnv, self_, _m_JsonParser__getValueAsBoolean); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__getValueAsBoolean1 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getValueAsBoolean1(jobject self_, uint8_t def) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getValueAsBoolean1, + "getValueAsBoolean", "(Z)Z"); + if (_m_JsonParser__getValueAsBoolean1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod( + jniEnv, self_, _m_JsonParser__getValueAsBoolean1, def); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__getValueAsString = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getValueAsString(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getValueAsString, + "getValueAsString", "()Ljava/lang/String;"); + if (_m_JsonParser__getValueAsString == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonParser__getValueAsString); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__getValueAsString1 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getValueAsString1(jobject self_, jobject def) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getValueAsString1, + "getValueAsString", "(Ljava/lang/String;)Ljava/lang/String;"); + if (_m_JsonParser__getValueAsString1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonParser__getValueAsString1, def); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__canReadObjectId = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__canReadObjectId(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__canReadObjectId, "canReadObjectId", + "()Z"); + if (_m_JsonParser__canReadObjectId == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod( + jniEnv, self_, _m_JsonParser__canReadObjectId); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__canReadTypeId = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__canReadTypeId(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__canReadTypeId, "canReadTypeId", + "()Z"); + if (_m_JsonParser__canReadTypeId == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = + (*jniEnv)->CallBooleanMethod(jniEnv, self_, _m_JsonParser__canReadTypeId); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser__getObjectId = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getObjectId(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getObjectId, "getObjectId", + "()Ljava/lang/Object;"); + if (_m_JsonParser__getObjectId == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_JsonParser__getObjectId); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__getTypeId = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__getTypeId(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__getTypeId, "getTypeId", + "()Ljava/lang/Object;"); + if (_m_JsonParser__getTypeId == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_JsonParser__getTypeId); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__readValueAs = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__readValueAs(jobject self_, jobject valueType) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__readValueAs, "readValueAs", + "(Ljava/lang/Class;)Ljava/lang/Object;"); + if (_m_JsonParser__readValueAs == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonParser__readValueAs, valueType); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__readValueAs1 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__readValueAs1(jobject self_, jobject valueTypeRef) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method( + _c_JsonParser, &_m_JsonParser__readValueAs1, "readValueAs", + "(Lcom/fasterxml/jackson/core/type/TypeReference;)Ljava/lang/Object;"); + if (_m_JsonParser__readValueAs1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonParser__readValueAs1, valueTypeRef); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__readValuesAs = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__readValuesAs(jobject self_, jobject valueType) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__readValuesAs, "readValuesAs", + "(Ljava/lang/Class;)Ljava/util/Iterator;"); + if (_m_JsonParser__readValuesAs == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonParser__readValuesAs, valueType); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__readValuesAs1 = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__readValuesAs1(jobject self_, jobject valueTypeRef) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method( + _c_JsonParser, &_m_JsonParser__readValuesAs1, "readValuesAs", + "(Lcom/fasterxml/jackson/core/type/TypeReference;)Ljava/util/Iterator;"); + if (_m_JsonParser__readValuesAs1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_JsonParser__readValuesAs1, valueTypeRef); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser__readValueAsTree = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser__readValueAsTree(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser, &_m_JsonParser__readValueAsTree, "readValueAsTree", + "()Lcom/fasterxml/jackson/core/TreeNode;"); + if (_m_JsonParser__readValueAsTree == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod(jniEnv, self_, + _m_JsonParser__readValueAsTree); + return to_global_ref_result(_result); +} + +jfieldID _f_JsonParser__DEFAULT_READ_CAPABILITIES = NULL; +FFI_PLUGIN_EXPORT +JniResult get_JsonParser__DEFAULT_READ_CAPABILITIES() { + load_env(); + load_class_global_ref(&_c_JsonParser, + "com/fasterxml/jackson/core/JsonParser"); + if (_c_JsonParser == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_JsonParser, &_f_JsonParser__DEFAULT_READ_CAPABILITIES, + "DEFAULT_READ_CAPABILITIES", + "Lcom/fasterxml/jackson/core/util/JacksonFeatureSet;"); + jobject _result = (*jniEnv)->GetStaticObjectField( + jniEnv, _c_JsonParser, _f_JsonParser__DEFAULT_READ_CAPABILITIES); + return to_global_ref_result(_result); +} + +// com.fasterxml.jackson.core.JsonParser$Feature +jclass _c_JsonParser_Feature = NULL; + +jmethodID _m_JsonParser_Feature__values = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser_Feature__values() { + load_env(); + load_class_global_ref(&_c_JsonParser_Feature, + "com/fasterxml/jackson/core/JsonParser$Feature"); + if (_c_JsonParser_Feature == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_JsonParser_Feature, &_m_JsonParser_Feature__values, + "values", + "()[Lcom/fasterxml/jackson/core/JsonParser$Feature;"); + if (_m_JsonParser_Feature__values == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_JsonParser_Feature, _m_JsonParser_Feature__values); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser_Feature__valueOf = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser_Feature__valueOf(jobject name) { + load_env(); + load_class_global_ref(&_c_JsonParser_Feature, + "com/fasterxml/jackson/core/JsonParser$Feature"); + if (_c_JsonParser_Feature == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method( + _c_JsonParser_Feature, &_m_JsonParser_Feature__valueOf, "valueOf", + "(Ljava/lang/String;)Lcom/fasterxml/jackson/core/JsonParser$Feature;"); + if (_m_JsonParser_Feature__valueOf == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_JsonParser_Feature, _m_JsonParser_Feature__valueOf, name); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser_Feature__collectDefaults = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser_Feature__collectDefaults() { + load_env(); + load_class_global_ref(&_c_JsonParser_Feature, + "com/fasterxml/jackson/core/JsonParser$Feature"); + if (_c_JsonParser_Feature == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_JsonParser_Feature, + &_m_JsonParser_Feature__collectDefaults, "collectDefaults", + "()I"); + if (_m_JsonParser_Feature__collectDefaults == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = (*jniEnv)->CallStaticIntMethod( + jniEnv, _c_JsonParser_Feature, _m_JsonParser_Feature__collectDefaults); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser_Feature__enabledByDefault = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser_Feature__enabledByDefault(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser_Feature, + "com/fasterxml/jackson/core/JsonParser$Feature"); + if (_c_JsonParser_Feature == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser_Feature, &_m_JsonParser_Feature__enabledByDefault, + "enabledByDefault", "()Z"); + if (_m_JsonParser_Feature__enabledByDefault == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod( + jniEnv, self_, _m_JsonParser_Feature__enabledByDefault); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser_Feature__enabledIn = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser_Feature__enabledIn(jobject self_, int32_t flags) { + load_env(); + load_class_global_ref(&_c_JsonParser_Feature, + "com/fasterxml/jackson/core/JsonParser$Feature"); + if (_c_JsonParser_Feature == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser_Feature, &_m_JsonParser_Feature__enabledIn, + "enabledIn", "(I)Z"); + if (_m_JsonParser_Feature__enabledIn == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = (*jniEnv)->CallBooleanMethod( + jniEnv, self_, _m_JsonParser_Feature__enabledIn, flags); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonParser_Feature__getMask = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser_Feature__getMask(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonParser_Feature, + "com/fasterxml/jackson/core/JsonParser$Feature"); + if (_c_JsonParser_Feature == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonParser_Feature, &_m_JsonParser_Feature__getMask, "getMask", + "()I"); + if (_m_JsonParser_Feature__getMask == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = + (*jniEnv)->CallIntMethod(jniEnv, self_, _m_JsonParser_Feature__getMask); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +// com.fasterxml.jackson.core.JsonParser$NumberType +jclass _c_JsonParser_NumberType = NULL; + +jmethodID _m_JsonParser_NumberType__values = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser_NumberType__values() { + load_env(); + load_class_global_ref(&_c_JsonParser_NumberType, + "com/fasterxml/jackson/core/JsonParser$NumberType"); + if (_c_JsonParser_NumberType == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_JsonParser_NumberType, + &_m_JsonParser_NumberType__values, "values", + "()[Lcom/fasterxml/jackson/core/JsonParser$NumberType;"); + if (_m_JsonParser_NumberType__values == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_JsonParser_NumberType, _m_JsonParser_NumberType__values); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonParser_NumberType__valueOf = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonParser_NumberType__valueOf(jobject name) { + load_env(); + load_class_global_ref(&_c_JsonParser_NumberType, + "com/fasterxml/jackson/core/JsonParser$NumberType"); + if (_c_JsonParser_NumberType == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method( + _c_JsonParser_NumberType, &_m_JsonParser_NumberType__valueOf, "valueOf", + "(Ljava/lang/String;)Lcom/fasterxml/jackson/core/JsonParser$NumberType;"); + if (_m_JsonParser_NumberType__valueOf == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_JsonParser_NumberType, _m_JsonParser_NumberType__valueOf, + name); + return to_global_ref_result(_result); +} + +// com.fasterxml.jackson.core.JsonToken +jclass _c_JsonToken = NULL; + +jmethodID _m_JsonToken__values = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonToken__values() { + load_env(); + load_class_global_ref(&_c_JsonToken, "com/fasterxml/jackson/core/JsonToken"); + if (_c_JsonToken == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_JsonToken, &_m_JsonToken__values, "values", + "()[Lcom/fasterxml/jackson/core/JsonToken;"); + if (_m_JsonToken__values == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod(jniEnv, _c_JsonToken, + _m_JsonToken__values); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonToken__valueOf = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonToken__valueOf(jobject name) { + load_env(); + load_class_global_ref(&_c_JsonToken, "com/fasterxml/jackson/core/JsonToken"); + if (_c_JsonToken == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method( + _c_JsonToken, &_m_JsonToken__valueOf, "valueOf", + "(Ljava/lang/String;)Lcom/fasterxml/jackson/core/JsonToken;"); + if (_m_JsonToken__valueOf == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_JsonToken, _m_JsonToken__valueOf, name); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonToken__id = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonToken__id(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonToken, "com/fasterxml/jackson/core/JsonToken"); + if (_c_JsonToken == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonToken, &_m_JsonToken__id, "id", "()I"); + if (_m_JsonToken__id == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = (*jniEnv)->CallIntMethod(jniEnv, self_, _m_JsonToken__id); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonToken__asString = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonToken__asString(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonToken, "com/fasterxml/jackson/core/JsonToken"); + if (_c_JsonToken == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonToken, &_m_JsonToken__asString, "asString", + "()Ljava/lang/String;"); + if (_m_JsonToken__asString == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_JsonToken__asString); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonToken__asCharArray = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonToken__asCharArray(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonToken, "com/fasterxml/jackson/core/JsonToken"); + if (_c_JsonToken == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonToken, &_m_JsonToken__asCharArray, "asCharArray", "()[C"); + if (_m_JsonToken__asCharArray == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_JsonToken__asCharArray); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonToken__asByteArray = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonToken__asByteArray(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonToken, "com/fasterxml/jackson/core/JsonToken"); + if (_c_JsonToken == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonToken, &_m_JsonToken__asByteArray, "asByteArray", "()[B"); + if (_m_JsonToken__asByteArray == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_JsonToken__asByteArray); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonToken__isNumeric = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonToken__isNumeric(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonToken, "com/fasterxml/jackson/core/JsonToken"); + if (_c_JsonToken == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonToken, &_m_JsonToken__isNumeric, "isNumeric", "()Z"); + if (_m_JsonToken__isNumeric == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = + (*jniEnv)->CallBooleanMethod(jniEnv, self_, _m_JsonToken__isNumeric); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonToken__isStructStart = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonToken__isStructStart(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonToken, "com/fasterxml/jackson/core/JsonToken"); + if (_c_JsonToken == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonToken, &_m_JsonToken__isStructStart, "isStructStart", + "()Z"); + if (_m_JsonToken__isStructStart == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = + (*jniEnv)->CallBooleanMethod(jniEnv, self_, _m_JsonToken__isStructStart); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonToken__isStructEnd = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonToken__isStructEnd(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonToken, "com/fasterxml/jackson/core/JsonToken"); + if (_c_JsonToken == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonToken, &_m_JsonToken__isStructEnd, "isStructEnd", "()Z"); + if (_m_JsonToken__isStructEnd == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = + (*jniEnv)->CallBooleanMethod(jniEnv, self_, _m_JsonToken__isStructEnd); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonToken__isScalarValue = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonToken__isScalarValue(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonToken, "com/fasterxml/jackson/core/JsonToken"); + if (_c_JsonToken == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonToken, &_m_JsonToken__isScalarValue, "isScalarValue", + "()Z"); + if (_m_JsonToken__isScalarValue == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = + (*jniEnv)->CallBooleanMethod(jniEnv, self_, _m_JsonToken__isScalarValue); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_JsonToken__isBoolean = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonToken__isBoolean(jobject self_) { + load_env(); + load_class_global_ref(&_c_JsonToken, "com/fasterxml/jackson/core/JsonToken"); + if (_c_JsonToken == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_JsonToken, &_m_JsonToken__isBoolean, "isBoolean", "()Z"); + if (_m_JsonToken__isBoolean == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = + (*jniEnv)->CallBooleanMethod(jniEnv, self_, _m_JsonToken__isBoolean); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} diff --git a/pkgs/jnigen/test/jackson_core_test/third_party/c_based/dart_bindings/_init.dart b/pkgs/jnigen/test/jackson_core_test/third_party/c_based/dart_bindings/_init.dart new file mode 100644 index 000000000..8018e7d3c --- /dev/null +++ b/pkgs/jnigen/test/jackson_core_test/third_party/c_based/dart_bindings/_init.dart @@ -0,0 +1,24 @@ +// Generated from jackson-core which is licensed under the Apache License 2.0. +// The following copyright from the original authors applies. +// See https://github.com/FasterXML/jackson-core/blob/2.14/LICENSE +// +// Copyright (c) 2007 - The Jackson Project Authors +// Licensed under the Apache License, Version 2.0 (the "License") +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import "dart:ffi" as ffi; +import "package:jni/internal_helpers_for_jnigen.dart"; + +// Auto-generated initialization code. + +final ffi.Pointer Function(String sym) jniLookup = + ProtectedJniExtensions.initGeneratedLibrary("jackson_core"); diff --git a/pkgs/jnigen/test/jackson_core_test/third_party/c_based/dart_bindings/com/fasterxml/jackson/core/JsonFactory.dart b/pkgs/jnigen/test/jackson_core_test/third_party/c_based/dart_bindings/com/fasterxml/jackson/core/JsonFactory.dart new file mode 100644 index 000000000..95ddfd579 --- /dev/null +++ b/pkgs/jnigen/test/jackson_core_test/third_party/c_based/dart_bindings/com/fasterxml/jackson/core/JsonFactory.dart @@ -0,0 +1,1996 @@ +// Generated from jackson-core which is licensed under the Apache License 2.0. +// The following copyright from the original authors applies. +// See https://github.com/FasterXML/jackson-core/blob/2.14/LICENSE +// +// Copyright (c) 2007 - The Jackson Project Authors +// Licensed under the Apache License, Version 2.0 (the "License") +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Autogenerated by jnigen. DO NOT EDIT! + +// ignore_for_file: annotate_overrides +// ignore_for_file: camel_case_extensions +// ignore_for_file: camel_case_types +// ignore_for_file: constant_identifier_names +// ignore_for_file: file_names +// ignore_for_file: lines_longer_than_80_chars +// ignore_for_file: no_leading_underscores_for_local_identifiers +// ignore_for_file: non_constant_identifier_names +// ignore_for_file: overridden_fields +// ignore_for_file: unnecessary_cast +// ignore_for_file: unused_element +// ignore_for_file: unused_field +// ignore_for_file: unused_import +// ignore_for_file: unused_local_variable +// ignore_for_file: unused_shown_name + +import "dart:isolate" show ReceivePort; +import "dart:ffi" as ffi; +import "package:jni/internal_helpers_for_jnigen.dart"; +import "package:jni/jni.dart" as jni; + +import "JsonParser.dart" as jsonparser_; +import "../../../../_init.dart"; + +/// from: com.fasterxml.jackson.core.JsonFactory +/// +/// The main factory class of Jackson package, used to configure and +/// construct reader (aka parser, JsonParser) +/// and writer (aka generator, JsonGenerator) +/// instances. +/// +/// Factory instances are thread-safe and reusable after configuration +/// (if any). Typically applications and services use only a single +/// globally shared factory instance, unless they need differently +/// configured factories. Factory reuse is important if efficiency matters; +/// most recycling of expensive construct is done on per-factory basis. +/// +/// Creation of a factory instance is a light-weight operation, +/// and since there is no need for pluggable alternative implementations +/// (as there is no "standard" JSON processor API to implement), +/// the default constructor is used for constructing factory +/// instances. +///@author Tatu Saloranta +class JsonFactory extends jni.JObject { + @override + late final jni.JObjType $type = type; + + JsonFactory.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $JsonFactoryType(); + + /// from: static public final java.lang.String FORMAT_NAME_JSON + /// + /// Name used to identify JSON format + /// (and returned by \#getFormatName() + static const FORMAT_NAME_JSON = r"""JSON"""; + + static final _get_DEFAULT_FACTORY_FEATURE_FLAGS = + jniLookup>( + "get_JsonFactory__DEFAULT_FACTORY_FEATURE_FLAGS") + .asFunction(); + + /// from: static protected final int DEFAULT_FACTORY_FEATURE_FLAGS + /// + /// Bitfield (set of flags) of all factory features that are enabled by default. + static int get DEFAULT_FACTORY_FEATURE_FLAGS => + _get_DEFAULT_FACTORY_FEATURE_FLAGS().integer; + + static final _get_DEFAULT_PARSER_FEATURE_FLAGS = + jniLookup>( + "get_JsonFactory__DEFAULT_PARSER_FEATURE_FLAGS") + .asFunction(); + + /// from: static protected final int DEFAULT_PARSER_FEATURE_FLAGS + /// + /// Bitfield (set of flags) of all parser features that are enabled + /// by default. + static int get DEFAULT_PARSER_FEATURE_FLAGS => + _get_DEFAULT_PARSER_FEATURE_FLAGS().integer; + + static final _get_DEFAULT_GENERATOR_FEATURE_FLAGS = + jniLookup>( + "get_JsonFactory__DEFAULT_GENERATOR_FEATURE_FLAGS") + .asFunction(); + + /// from: static protected final int DEFAULT_GENERATOR_FEATURE_FLAGS + /// + /// Bitfield (set of flags) of all generator features that are enabled + /// by default. + static int get DEFAULT_GENERATOR_FEATURE_FLAGS => + _get_DEFAULT_GENERATOR_FEATURE_FLAGS().integer; + + static final _get_DEFAULT_ROOT_VALUE_SEPARATOR = + jniLookup>( + "get_JsonFactory__DEFAULT_ROOT_VALUE_SEPARATOR") + .asFunction(); + + /// from: static public final com.fasterxml.jackson.core.SerializableString DEFAULT_ROOT_VALUE_SEPARATOR + /// The returned object must be released after use, by calling the [release] method. + static jni.JObject get DEFAULT_ROOT_VALUE_SEPARATOR => const jni.JObjectType() + .fromRef(_get_DEFAULT_ROOT_VALUE_SEPARATOR().object); + + static final _new0 = jniLookup>( + "JsonFactory__new0") + .asFunction(); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + /// + /// Default constructor used to create factory instances. + /// Creation of a factory instance is a light-weight operation, + /// but it is still a good idea to reuse limited number of + /// factory instances (and quite often just a single instance): + /// factories are used as context for storing some reused + /// processing objects (such as symbol tables parsers use) + /// and this reuse only works within context of a single + /// factory instance. + factory JsonFactory() { + return JsonFactory.fromRef(_new0().object); + } + + static final _new1 = jniLookup< + ffi + .NativeFunction)>>( + "JsonFactory__new1") + .asFunction)>(); + + /// from: public void (com.fasterxml.jackson.core.ObjectCodec oc) + /// The returned object must be released after use, by calling the [release] method. + factory JsonFactory.new1( + jni.JObject oc, + ) { + return JsonFactory.fromRef(_new1(oc.reference).object); + } + + static final _new2 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__new2") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: protected void (com.fasterxml.jackson.core.JsonFactory src, com.fasterxml.jackson.core.ObjectCodec codec) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Constructor used when copy()ing a factory instance. + ///@param src Original factory to copy settings from + ///@param codec Databinding-level codec to use, if any + ///@since 2.2.1 + factory JsonFactory.new2( + JsonFactory src, + jni.JObject codec, + ) { + return JsonFactory.fromRef(_new2(src.reference, codec.reference).object); + } + + static final _new3 = jniLookup< + ffi + .NativeFunction)>>( + "JsonFactory__new3") + .asFunction)>(); + + /// from: public void (com.fasterxml.jackson.core.JsonFactoryBuilder b) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Constructor used by JsonFactoryBuilder for instantiation. + ///@param b Builder that contains settings to use + ///@since 2.10 + factory JsonFactory.new3( + jni.JObject b, + ) { + return JsonFactory.fromRef(_new3(b.reference).object); + } + + static final _new4 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Uint8)>>("JsonFactory__new4") + .asFunction, int)>(); + + /// from: protected void (com.fasterxml.jackson.core.TSFBuilder b, boolean bogus) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Constructor for subtypes; needed to work around the fact that before 3.0, + /// this factory has cumbersome dual role as generic type as well as actual + /// implementation for json. + ///@param b Builder that contains settings to use + ///@param bogus Argument only needed to separate constructor signature; ignored + factory JsonFactory.new4( + jni.JObject b, + bool bogus, + ) { + return JsonFactory.fromRef(_new4(b.reference, bogus ? 1 : 0).object); + } + + static final _rebuild = jniLookup< + ffi + .NativeFunction)>>( + "JsonFactory__rebuild") + .asFunction)>(); + + /// from: public com.fasterxml.jackson.core.TSFBuilder rebuild() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that allows construction of differently configured factory, starting + /// with settings of this factory. + ///@return Builder instance to use + ///@since 2.10 + jni.JObject rebuild() { + return const jni.JObjectType().fromRef(_rebuild(reference).object); + } + + static final _builder = + jniLookup>( + "JsonFactory__builder") + .asFunction(); + + /// from: static public com.fasterxml.jackson.core.TSFBuilder builder() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Main factory method to use for constructing JsonFactory instances with + /// different configuration: creates and returns a builder for collecting configuration + /// settings; instance created by calling {@code build()} after all configuration + /// set. + /// + /// NOTE: signature unfortunately does not expose true implementation type; this + /// will be fixed in 3.0. + ///@return Builder instance to use + static jni.JObject builder() { + return const jni.JObjectType().fromRef(_builder().object); + } + + static final _copy = jniLookup< + ffi + .NativeFunction)>>( + "JsonFactory__copy") + .asFunction)>(); + + /// from: public com.fasterxml.jackson.core.JsonFactory copy() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing a new JsonFactory that has + /// the same settings as this instance, but is otherwise + /// independent (i.e. nothing is actually shared, symbol tables + /// are separate). + /// Note that ObjectCodec reference is not copied but is + /// set to null; caller typically needs to set it after calling + /// this method. Reason for this is that the codec is used for + /// callbacks, and assumption is that there is strict 1-to-1 + /// mapping between codec, factory. Caller has to, then, explicitly + /// set codec after making the copy. + ///@return Copy of this factory instance + ///@since 2.1 + JsonFactory copy() { + return const $JsonFactoryType().fromRef(_copy(reference).object); + } + + static final _readResolve = jniLookup< + ffi + .NativeFunction)>>( + "JsonFactory__readResolve") + .asFunction)>(); + + /// from: protected java.lang.Object readResolve() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that we need to override to actually make restoration go + /// through constructors etc: needed to allow JDK serializability of + /// factory instances. + /// + /// Note: must be overridden by sub-classes as well. + ///@return Newly constructed instance + jni.JObject readResolve() { + return const jni.JObjectType().fromRef(_readResolve(reference).object); + } + + static final _requiresPropertyOrdering = jniLookup< + ffi + .NativeFunction)>>( + "JsonFactory__requiresPropertyOrdering") + .asFunction)>(); + + /// from: public boolean requiresPropertyOrdering() + /// + /// Introspection method that higher-level functionality may call + /// to see whether underlying data format requires a stable ordering + /// of object properties or not. + /// This is usually used for determining + /// whether to force a stable ordering (like alphabetic ordering by name) + /// if no ordering if explicitly specified. + /// + /// Default implementation returns false as JSON does NOT + /// require stable ordering. Formats that require ordering include positional + /// textual formats like CSV, and schema-based binary formats + /// like Avro. + ///@return Whether format supported by this factory + /// requires Object properties to be ordered. + ///@since 2.3 + bool requiresPropertyOrdering() { + return _requiresPropertyOrdering(reference).boolean; + } + + static final _canHandleBinaryNatively = jniLookup< + ffi + .NativeFunction)>>( + "JsonFactory__canHandleBinaryNatively") + .asFunction)>(); + + /// from: public boolean canHandleBinaryNatively() + /// + /// Introspection method that higher-level functionality may call + /// to see whether underlying data format can read and write binary + /// data natively; that is, embeded it as-is without using encodings + /// such as Base64. + /// + /// Default implementation returns false as JSON does not + /// support native access: all binary content must use Base64 encoding. + /// Most binary formats (like Smile and Avro) support native binary content. + ///@return Whether format supported by this factory + /// supports native binary content + ///@since 2.3 + bool canHandleBinaryNatively() { + return _canHandleBinaryNatively(reference).boolean; + } + + static final _canUseCharArrays = jniLookup< + ffi + .NativeFunction)>>( + "JsonFactory__canUseCharArrays") + .asFunction)>(); + + /// from: public boolean canUseCharArrays() + /// + /// Introspection method that can be used by base factory to check + /// whether access using char[] is something that actual + /// parser implementations can take advantage of, over having to + /// use java.io.Reader. Sub-types are expected to override + /// definition; default implementation (suitable for JSON) alleges + /// that optimization are possible; and thereby is likely to try + /// to access java.lang.String content by first copying it into + /// recyclable intermediate buffer. + ///@return Whether access to decoded textual content can be efficiently + /// accessed using parser method {@code getTextCharacters()}. + ///@since 2.4 + bool canUseCharArrays() { + return _canUseCharArrays(reference).boolean; + } + + static final _canParseAsync = jniLookup< + ffi + .NativeFunction)>>( + "JsonFactory__canParseAsync") + .asFunction)>(); + + /// from: public boolean canParseAsync() + /// + /// Introspection method that can be used to check whether this + /// factory can create non-blocking parsers: parsers that do not + /// use blocking I/O abstractions but instead use a + /// com.fasterxml.jackson.core.async.NonBlockingInputFeeder. + ///@return Whether this factory supports non-blocking ("async") parsing or + /// not (and consequently whether {@code createNonBlockingXxx()} method(s) work) + ///@since 2.9 + bool canParseAsync() { + return _canParseAsync(reference).boolean; + } + + static final _getFormatReadFeatureType = jniLookup< + ffi + .NativeFunction)>>( + "JsonFactory__getFormatReadFeatureType") + .asFunction)>(); + + /// from: public java.lang.Class getFormatReadFeatureType() + /// The returned object must be released after use, by calling the [release] method. + jni.JObject getFormatReadFeatureType() { + return const jni.JObjectType() + .fromRef(_getFormatReadFeatureType(reference).object); + } + + static final _getFormatWriteFeatureType = jniLookup< + ffi + .NativeFunction)>>( + "JsonFactory__getFormatWriteFeatureType") + .asFunction)>(); + + /// from: public java.lang.Class getFormatWriteFeatureType() + /// The returned object must be released after use, by calling the [release] method. + jni.JObject getFormatWriteFeatureType() { + return const jni.JObjectType() + .fromRef(_getFormatWriteFeatureType(reference).object); + } + + static final _canUseSchema = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__canUseSchema") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public boolean canUseSchema(com.fasterxml.jackson.core.FormatSchema schema) + /// + /// Method that can be used to quickly check whether given schema + /// is something that parsers and/or generators constructed by this + /// factory could use. Note that this means possible use, at the level + /// of data format (i.e. schema is for same data format as parsers and + /// generators this factory constructs); individual schema instances + /// may have further usage restrictions. + ///@param schema Schema instance to check + ///@return Whether parsers and generators constructed by this factory + /// can use specified format schema instance + bool canUseSchema( + jni.JObject schema, + ) { + return _canUseSchema(reference, schema.reference).boolean; + } + + static final _getFormatName = jniLookup< + ffi + .NativeFunction)>>( + "JsonFactory__getFormatName") + .asFunction)>(); + + /// from: public java.lang.String getFormatName() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that returns short textual id identifying format + /// this factory supports. + /// + /// Note: sub-classes should override this method; default + /// implementation will return null for all sub-classes + ///@return Name of the format handled by parsers, generators this factory creates + jni.JString getFormatName() { + return const jni.JStringType().fromRef(_getFormatName(reference).object); + } + + static final _hasFormat = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__hasFormat") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public com.fasterxml.jackson.core.format.MatchStrength hasFormat(com.fasterxml.jackson.core.format.InputAccessor acc) + /// The returned object must be released after use, by calling the [release] method. + jni.JObject hasFormat( + jni.JObject acc, + ) { + return const jni.JObjectType() + .fromRef(_hasFormat(reference, acc.reference).object); + } + + static final _requiresCustomCodec = jniLookup< + ffi + .NativeFunction)>>( + "JsonFactory__requiresCustomCodec") + .asFunction)>(); + + /// from: public boolean requiresCustomCodec() + /// + /// Method that can be called to determine if a custom + /// ObjectCodec is needed for binding data parsed + /// using JsonParser constructed by this factory + /// (which typically also implies the same for serialization + /// with JsonGenerator). + ///@return True if custom codec is needed with parsers and + /// generators created by this factory; false if a general + /// ObjectCodec is enough + ///@since 2.1 + bool requiresCustomCodec() { + return _requiresCustomCodec(reference).boolean; + } + + static final _hasJSONFormat = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__hasJSONFormat") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: protected com.fasterxml.jackson.core.format.MatchStrength hasJSONFormat(com.fasterxml.jackson.core.format.InputAccessor acc) + /// The returned object must be released after use, by calling the [release] method. + jni.JObject hasJSONFormat( + jni.JObject acc, + ) { + return const jni.JObjectType() + .fromRef(_hasJSONFormat(reference, acc.reference).object); + } + + static final _version = jniLookup< + ffi + .NativeFunction)>>( + "JsonFactory__version") + .asFunction)>(); + + /// from: public com.fasterxml.jackson.core.Version version() + /// The returned object must be released after use, by calling the [release] method. + jni.JObject version() { + return const jni.JObjectType().fromRef(_version(reference).object); + } + + static final _configure = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer, ffi.Uint8)>>("JsonFactory__configure") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer, int)>(); + + /// from: public final com.fasterxml.jackson.core.JsonFactory configure(com.fasterxml.jackson.core.JsonFactory.Feature f, boolean state) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for enabling or disabling specified parser feature + /// (check JsonParser.Feature for list of features) + ///@param f Feature to enable/disable + ///@param state Whether to enable or disable the feature + ///@return This factory instance (to allow call chaining) + ///@deprecated since 2.10 use JsonFactoryBuilder\#configure(JsonFactory.Feature, boolean) instead + JsonFactory configure( + JsonFactory_Feature f, + bool state, + ) { + return const $JsonFactoryType() + .fromRef(_configure(reference, f.reference, state ? 1 : 0).object); + } + + static final _enable = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__enable") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public com.fasterxml.jackson.core.JsonFactory enable(com.fasterxml.jackson.core.JsonFactory.Feature f) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for enabling specified parser feature + /// (check JsonFactory.Feature for list of features) + ///@param f Feature to enable + ///@return This factory instance (to allow call chaining) + ///@deprecated since 2.10 use JsonFactoryBuilder\#configure(JsonFactory.Feature, boolean) instead + JsonFactory enable( + JsonFactory_Feature f, + ) { + return const $JsonFactoryType() + .fromRef(_enable(reference, f.reference).object); + } + + static final _disable = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__disable") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public com.fasterxml.jackson.core.JsonFactory disable(com.fasterxml.jackson.core.JsonFactory.Feature f) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for disabling specified parser features + /// (check JsonFactory.Feature for list of features) + ///@param f Feature to disable + ///@return This factory instance (to allow call chaining) + ///@deprecated since 2.10 use JsonFactoryBuilder\#configure(JsonFactory.Feature, boolean) instead + JsonFactory disable( + JsonFactory_Feature f, + ) { + return const $JsonFactoryType() + .fromRef(_disable(reference, f.reference).object); + } + + static final _isEnabled = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__isEnabled") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public final boolean isEnabled(com.fasterxml.jackson.core.JsonFactory.Feature f) + /// + /// Checked whether specified parser feature is enabled. + ///@param f Feature to check + ///@return True if the specified feature is enabled + bool isEnabled( + JsonFactory_Feature f, + ) { + return _isEnabled(reference, f.reference).boolean; + } + + static final _getParserFeatures = jniLookup< + ffi + .NativeFunction)>>( + "JsonFactory__getParserFeatures") + .asFunction)>(); + + /// from: public final int getParserFeatures() + int getParserFeatures() { + return _getParserFeatures(reference).integer; + } + + static final _getGeneratorFeatures = jniLookup< + ffi + .NativeFunction)>>( + "JsonFactory__getGeneratorFeatures") + .asFunction)>(); + + /// from: public final int getGeneratorFeatures() + int getGeneratorFeatures() { + return _getGeneratorFeatures(reference).integer; + } + + static final _getFormatParserFeatures = jniLookup< + ffi + .NativeFunction)>>( + "JsonFactory__getFormatParserFeatures") + .asFunction)>(); + + /// from: public int getFormatParserFeatures() + int getFormatParserFeatures() { + return _getFormatParserFeatures(reference).integer; + } + + static final _getFormatGeneratorFeatures = jniLookup< + ffi + .NativeFunction)>>( + "JsonFactory__getFormatGeneratorFeatures") + .asFunction)>(); + + /// from: public int getFormatGeneratorFeatures() + int getFormatGeneratorFeatures() { + return _getFormatGeneratorFeatures(reference).integer; + } + + static final _configure1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer, ffi.Uint8)>>("JsonFactory__configure1") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer, int)>(); + + /// from: public final com.fasterxml.jackson.core.JsonFactory configure(com.fasterxml.jackson.core.JsonParser.Feature f, boolean state) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for enabling or disabling specified parser feature + /// (check JsonParser.Feature for list of features) + ///@param f Feature to enable/disable + ///@param state Whether to enable or disable the feature + ///@return This factory instance (to allow call chaining) + JsonFactory configure1( + jsonparser_.JsonParser_Feature f, + bool state, + ) { + return const $JsonFactoryType() + .fromRef(_configure1(reference, f.reference, state ? 1 : 0).object); + } + + static final _enable1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__enable1") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public com.fasterxml.jackson.core.JsonFactory enable(com.fasterxml.jackson.core.JsonParser.Feature f) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for enabling specified parser feature + /// (check JsonParser.Feature for list of features) + ///@param f Feature to enable + ///@return This factory instance (to allow call chaining) + JsonFactory enable1( + jsonparser_.JsonParser_Feature f, + ) { + return const $JsonFactoryType() + .fromRef(_enable1(reference, f.reference).object); + } + + static final _disable1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__disable1") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public com.fasterxml.jackson.core.JsonFactory disable(com.fasterxml.jackson.core.JsonParser.Feature f) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for disabling specified parser features + /// (check JsonParser.Feature for list of features) + ///@param f Feature to disable + ///@return This factory instance (to allow call chaining) + JsonFactory disable1( + jsonparser_.JsonParser_Feature f, + ) { + return const $JsonFactoryType() + .fromRef(_disable1(reference, f.reference).object); + } + + static final _isEnabled1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__isEnabled1") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public final boolean isEnabled(com.fasterxml.jackson.core.JsonParser.Feature f) + /// + /// Method for checking if the specified parser feature is enabled. + ///@param f Feature to check + ///@return True if specified feature is enabled + bool isEnabled1( + jsonparser_.JsonParser_Feature f, + ) { + return _isEnabled1(reference, f.reference).boolean; + } + + static final _isEnabled2 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__isEnabled2") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public final boolean isEnabled(com.fasterxml.jackson.core.StreamReadFeature f) + /// + /// Method for checking if the specified stream read feature is enabled. + ///@param f Feature to check + ///@return True if specified feature is enabled + ///@since 2.10 + bool isEnabled2( + jni.JObject f, + ) { + return _isEnabled2(reference, f.reference).boolean; + } + + static final _getInputDecorator = jniLookup< + ffi + .NativeFunction)>>( + "JsonFactory__getInputDecorator") + .asFunction)>(); + + /// from: public com.fasterxml.jackson.core.io.InputDecorator getInputDecorator() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for getting currently configured input decorator (if any; + /// there is no default decorator). + ///@return InputDecorator configured, if any + jni.JObject getInputDecorator() { + return const jni.JObjectType() + .fromRef(_getInputDecorator(reference).object); + } + + static final _setInputDecorator = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__setInputDecorator") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public com.fasterxml.jackson.core.JsonFactory setInputDecorator(com.fasterxml.jackson.core.io.InputDecorator d) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for overriding currently configured input decorator + ///@param d Decorator to configure for this factory, if any ({@code null} if none) + ///@return This factory instance (to allow call chaining) + ///@deprecated Since 2.10 use JsonFactoryBuilder\#inputDecorator(InputDecorator) instead + JsonFactory setInputDecorator( + jni.JObject d, + ) { + return const $JsonFactoryType() + .fromRef(_setInputDecorator(reference, d.reference).object); + } + + static final _configure2 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer, ffi.Uint8)>>("JsonFactory__configure2") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer, int)>(); + + /// from: public final com.fasterxml.jackson.core.JsonFactory configure(com.fasterxml.jackson.core.JsonGenerator.Feature f, boolean state) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for enabling or disabling specified generator feature + /// (check JsonGenerator.Feature for list of features) + ///@param f Feature to enable/disable + ///@param state Whether to enable or disable the feature + ///@return This factory instance (to allow call chaining) + JsonFactory configure2( + jni.JObject f, + bool state, + ) { + return const $JsonFactoryType() + .fromRef(_configure2(reference, f.reference, state ? 1 : 0).object); + } + + static final _enable2 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__enable2") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public com.fasterxml.jackson.core.JsonFactory enable(com.fasterxml.jackson.core.JsonGenerator.Feature f) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for enabling specified generator features + /// (check JsonGenerator.Feature for list of features) + ///@param f Feature to enable + ///@return This factory instance (to allow call chaining) + JsonFactory enable2( + jni.JObject f, + ) { + return const $JsonFactoryType() + .fromRef(_enable2(reference, f.reference).object); + } + + static final _disable2 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__disable2") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public com.fasterxml.jackson.core.JsonFactory disable(com.fasterxml.jackson.core.JsonGenerator.Feature f) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for disabling specified generator feature + /// (check JsonGenerator.Feature for list of features) + ///@param f Feature to disable + ///@return This factory instance (to allow call chaining) + JsonFactory disable2( + jni.JObject f, + ) { + return const $JsonFactoryType() + .fromRef(_disable2(reference, f.reference).object); + } + + static final _isEnabled3 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__isEnabled3") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public final boolean isEnabled(com.fasterxml.jackson.core.JsonGenerator.Feature f) + /// + /// Check whether specified generator feature is enabled. + ///@param f Feature to check + ///@return Whether specified feature is enabled + bool isEnabled3( + jni.JObject f, + ) { + return _isEnabled3(reference, f.reference).boolean; + } + + static final _isEnabled4 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__isEnabled4") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public final boolean isEnabled(com.fasterxml.jackson.core.StreamWriteFeature f) + /// + /// Check whether specified stream write feature is enabled. + ///@param f Feature to check + ///@return Whether specified feature is enabled + ///@since 2.10 + bool isEnabled4( + jni.JObject f, + ) { + return _isEnabled4(reference, f.reference).boolean; + } + + static final _getCharacterEscapes = jniLookup< + ffi + .NativeFunction)>>( + "JsonFactory__getCharacterEscapes") + .asFunction)>(); + + /// from: public com.fasterxml.jackson.core.io.CharacterEscapes getCharacterEscapes() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for accessing custom escapes factory uses for JsonGenerators + /// it creates. + ///@return Configured {@code CharacterEscapes}, if any; {@code null} if none + jni.JObject getCharacterEscapes() { + return const jni.JObjectType() + .fromRef(_getCharacterEscapes(reference).object); + } + + static final _setCharacterEscapes = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__setCharacterEscapes") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public com.fasterxml.jackson.core.JsonFactory setCharacterEscapes(com.fasterxml.jackson.core.io.CharacterEscapes esc) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for defining custom escapes factory uses for JsonGenerators + /// it creates. + ///@param esc CharaterEscapes to set (or {@code null} for "none") + ///@return This factory instance (to allow call chaining) + JsonFactory setCharacterEscapes( + jni.JObject esc, + ) { + return const $JsonFactoryType() + .fromRef(_setCharacterEscapes(reference, esc.reference).object); + } + + static final _getOutputDecorator = jniLookup< + ffi + .NativeFunction)>>( + "JsonFactory__getOutputDecorator") + .asFunction)>(); + + /// from: public com.fasterxml.jackson.core.io.OutputDecorator getOutputDecorator() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for getting currently configured output decorator (if any; + /// there is no default decorator). + ///@return OutputDecorator configured for generators factory creates, if any; + /// {@code null} if none. + jni.JObject getOutputDecorator() { + return const jni.JObjectType() + .fromRef(_getOutputDecorator(reference).object); + } + + static final _setOutputDecorator = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__setOutputDecorator") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public com.fasterxml.jackson.core.JsonFactory setOutputDecorator(com.fasterxml.jackson.core.io.OutputDecorator d) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for overriding currently configured output decorator + ///@return This factory instance (to allow call chaining) + ///@param d Output decorator to use, if any + ///@deprecated Since 2.10 use JsonFactoryBuilder\#outputDecorator(OutputDecorator) instead + JsonFactory setOutputDecorator( + jni.JObject d, + ) { + return const $JsonFactoryType() + .fromRef(_setOutputDecorator(reference, d.reference).object); + } + + static final _setRootValueSeparator = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__setRootValueSeparator") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public com.fasterxml.jackson.core.JsonFactory setRootValueSeparator(java.lang.String sep) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that allows overriding String used for separating root-level + /// JSON values (default is single space character) + ///@param sep Separator to use, if any; null means that no separator is + /// automatically added + ///@return This factory instance (to allow call chaining) + JsonFactory setRootValueSeparator( + jni.JString sep, + ) { + return const $JsonFactoryType() + .fromRef(_setRootValueSeparator(reference, sep.reference).object); + } + + static final _getRootValueSeparator = jniLookup< + ffi + .NativeFunction)>>( + "JsonFactory__getRootValueSeparator") + .asFunction)>(); + + /// from: public java.lang.String getRootValueSeparator() + /// The returned object must be released after use, by calling the [release] method. + /// + /// @return Root value separator configured, if any + jni.JString getRootValueSeparator() { + return const jni.JStringType() + .fromRef(_getRootValueSeparator(reference).object); + } + + static final _setCodec = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__setCodec") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public com.fasterxml.jackson.core.JsonFactory setCodec(com.fasterxml.jackson.core.ObjectCodec oc) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for associating a ObjectCodec (typically + /// a com.fasterxml.jackson.databind.ObjectMapper) + /// with this factory (and more importantly, parsers and generators + /// it constructs). This is needed to use data-binding methods + /// of JsonParser and JsonGenerator instances. + ///@param oc Codec to use + ///@return This factory instance (to allow call chaining) + JsonFactory setCodec( + jni.JObject oc, + ) { + return const $JsonFactoryType() + .fromRef(_setCodec(reference, oc.reference).object); + } + + static final _getCodec = jniLookup< + ffi + .NativeFunction)>>( + "JsonFactory__getCodec") + .asFunction)>(); + + /// from: public com.fasterxml.jackson.core.ObjectCodec getCodec() + /// The returned object must be released after use, by calling the [release] method. + jni.JObject getCodec() { + return const jni.JObjectType().fromRef(_getCodec(reference).object); + } + + static final _createParser = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__createParser") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public com.fasterxml.jackson.core.JsonParser createParser(java.io.File f) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing JSON parser instance to parse + /// contents of specified file. + /// + /// + /// Encoding is auto-detected from contents according to JSON + /// specification recommended mechanism. Json specification + /// supports only UTF-8, UTF-16 and UTF-32 as valid encodings, + /// so auto-detection implemented only for this charsets. + /// For other charsets use \#createParser(java.io.Reader). + /// + /// + /// Underlying input stream (needed for reading contents) + /// will be __owned__ (and managed, i.e. closed as need be) by + /// the parser, since caller has no access to it. + ///@param f File that contains JSON content to parse + ///@since 2.1 + jsonparser_.JsonParser createParser( + jni.JObject f, + ) { + return const jsonparser_.$JsonParserType() + .fromRef(_createParser(reference, f.reference).object); + } + + static final _createParser1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__createParser1") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public com.fasterxml.jackson.core.JsonParser createParser(java.net.URL url) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing JSON parser instance to parse + /// contents of resource reference by given URL. + /// + /// Encoding is auto-detected from contents according to JSON + /// specification recommended mechanism. Json specification + /// supports only UTF-8, UTF-16 and UTF-32 as valid encodings, + /// so auto-detection implemented only for this charsets. + /// For other charsets use \#createParser(java.io.Reader). + /// + /// Underlying input stream (needed for reading contents) + /// will be __owned__ (and managed, i.e. closed as need be) by + /// the parser, since caller has no access to it. + ///@param url URL pointing to resource that contains JSON content to parse + ///@since 2.1 + jsonparser_.JsonParser createParser1( + jni.JObject url, + ) { + return const jsonparser_.$JsonParserType() + .fromRef(_createParser1(reference, url.reference).object); + } + + static final _createParser2 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__createParser2") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public com.fasterxml.jackson.core.JsonParser createParser(java.io.InputStream in) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing JSON parser instance to parse + /// the contents accessed via specified input stream. + /// + /// The input stream will __not be owned__ by + /// the parser, it will still be managed (i.e. closed if + /// end-of-stream is reacher, or parser close method called) + /// if (and only if) com.fasterxml.jackson.core.StreamReadFeature\#AUTO_CLOSE_SOURCE + /// is enabled. + /// + /// + /// Note: no encoding argument is taken since it can always be + /// auto-detected as suggested by JSON RFC. Json specification + /// supports only UTF-8, UTF-16 and UTF-32 as valid encodings, + /// so auto-detection implemented only for this charsets. + /// For other charsets use \#createParser(java.io.Reader). + ///@param in InputStream to use for reading JSON content to parse + ///@since 2.1 + jsonparser_.JsonParser createParser2( + jni.JObject in0, + ) { + return const jsonparser_.$JsonParserType() + .fromRef(_createParser2(reference, in0.reference).object); + } + + static final _createParser3 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__createParser3") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public com.fasterxml.jackson.core.JsonParser createParser(java.io.Reader r) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing parser for parsing + /// the contents accessed via specified Reader. + /// + /// The read stream will __not be owned__ by + /// the parser, it will still be managed (i.e. closed if + /// end-of-stream is reacher, or parser close method called) + /// if (and only if) com.fasterxml.jackson.core.StreamReadFeature\#AUTO_CLOSE_SOURCE + /// is enabled. + ///@param r Reader to use for reading JSON content to parse + ///@since 2.1 + jsonparser_.JsonParser createParser3( + jni.JObject r, + ) { + return const jsonparser_.$JsonParserType() + .fromRef(_createParser3(reference, r.reference).object); + } + + static final _createParser4 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__createParser4") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public com.fasterxml.jackson.core.JsonParser createParser(byte[] data) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing parser for parsing + /// the contents of given byte array. + ///@since 2.1 + jsonparser_.JsonParser createParser4( + jni.JArray data, + ) { + return const jsonparser_.$JsonParserType() + .fromRef(_createParser4(reference, data.reference).object); + } + + static final _createParser5 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Int32, + ffi.Int32)>>("JsonFactory__createParser5") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer, int, int)>(); + + /// from: public com.fasterxml.jackson.core.JsonParser createParser(byte[] data, int offset, int len) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing parser for parsing + /// the contents of given byte array. + ///@param data Buffer that contains data to parse + ///@param offset Offset of the first data byte within buffer + ///@param len Length of contents to parse within buffer + ///@since 2.1 + jsonparser_.JsonParser createParser5( + jni.JArray data, + int offset, + int len, + ) { + return const jsonparser_.$JsonParserType() + .fromRef(_createParser5(reference, data.reference, offset, len).object); + } + + static final _createParser6 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__createParser6") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public com.fasterxml.jackson.core.JsonParser createParser(java.lang.String content) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing parser for parsing + /// contents of given String. + ///@since 2.1 + jsonparser_.JsonParser createParser6( + jni.JString content, + ) { + return const jsonparser_.$JsonParserType() + .fromRef(_createParser6(reference, content.reference).object); + } + + static final _createParser7 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__createParser7") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public com.fasterxml.jackson.core.JsonParser createParser(char[] content) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing parser for parsing + /// contents of given char array. + ///@since 2.4 + jsonparser_.JsonParser createParser7( + jni.JArray content, + ) { + return const jsonparser_.$JsonParserType() + .fromRef(_createParser7(reference, content.reference).object); + } + + static final _createParser8 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Int32, + ffi.Int32)>>("JsonFactory__createParser8") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer, int, int)>(); + + /// from: public com.fasterxml.jackson.core.JsonParser createParser(char[] content, int offset, int len) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing parser for parsing contents of given char array. + ///@since 2.4 + jsonparser_.JsonParser createParser8( + jni.JArray content, + int offset, + int len, + ) { + return const jsonparser_.$JsonParserType().fromRef( + _createParser8(reference, content.reference, offset, len).object); + } + + static final _createParser9 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__createParser9") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public com.fasterxml.jackson.core.JsonParser createParser(java.io.DataInput in) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Optional method for constructing parser for reading contents from specified DataInput + /// instance. + /// + /// If this factory does not support DataInput as source, + /// will throw UnsupportedOperationException + ///@since 2.8 + jsonparser_.JsonParser createParser9( + jni.JObject in0, + ) { + return const jsonparser_.$JsonParserType() + .fromRef(_createParser9(reference, in0.reference).object); + } + + static final _createNonBlockingByteArrayParser = jniLookup< + ffi + .NativeFunction)>>( + "JsonFactory__createNonBlockingByteArrayParser") + .asFunction)>(); + + /// from: public com.fasterxml.jackson.core.JsonParser createNonBlockingByteArrayParser() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Optional method for constructing parser for non-blocking parsing + /// via com.fasterxml.jackson.core.async.ByteArrayFeeder + /// interface (accessed using JsonParser\#getNonBlockingInputFeeder() + /// from constructed instance). + /// + /// If this factory does not support non-blocking parsing (either at all, + /// or from byte array), + /// will throw UnsupportedOperationException. + /// + /// Note that JSON-backed factory only supports parsing of UTF-8 encoded JSON content + /// (and US-ASCII since it is proper subset); other encodings are not supported + /// at this point. + ///@since 2.9 + jsonparser_.JsonParser createNonBlockingByteArrayParser() { + return const jsonparser_.$JsonParserType() + .fromRef(_createNonBlockingByteArrayParser(reference).object); + } + + static final _createGenerator = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>("JsonFactory__createGenerator") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); + + /// from: public com.fasterxml.jackson.core.JsonGenerator createGenerator(java.io.OutputStream out, com.fasterxml.jackson.core.JsonEncoding enc) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing JSON generator for writing JSON content + /// using specified output stream. + /// Encoding to use must be specified, and needs to be one of available + /// types (as per JSON specification). + /// + /// Underlying stream __is NOT owned__ by the generator constructed, + /// so that generator will NOT close the output stream when + /// JsonGenerator\#close is called (unless auto-closing + /// feature, + /// com.fasterxml.jackson.core.JsonGenerator.Feature\#AUTO_CLOSE_TARGET + /// is enabled). + /// Using application needs to close it explicitly if this is the case. + /// + /// Note: there are formats that use fixed encoding (like most binary data formats) + /// and that ignore passed in encoding. + ///@param out OutputStream to use for writing JSON content + ///@param enc Character encoding to use + ///@since 2.1 + jni.JObject createGenerator( + jni.JObject out, + jni.JObject enc, + ) { + return const jni.JObjectType().fromRef( + _createGenerator(reference, out.reference, enc.reference).object); + } + + static final _createGenerator1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__createGenerator1") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public com.fasterxml.jackson.core.JsonGenerator createGenerator(java.io.OutputStream out) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Convenience method for constructing generator that uses default + /// encoding of the format (UTF-8 for JSON and most other data formats). + /// + /// Note: there are formats that use fixed encoding (like most binary data formats). + ///@since 2.1 + jni.JObject createGenerator1( + jni.JObject out, + ) { + return const jni.JObjectType() + .fromRef(_createGenerator1(reference, out.reference).object); + } + + static final _createGenerator2 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__createGenerator2") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public com.fasterxml.jackson.core.JsonGenerator createGenerator(java.io.Writer w) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing JSON generator for writing JSON content + /// using specified Writer. + /// + /// Underlying stream __is NOT owned__ by the generator constructed, + /// so that generator will NOT close the Reader when + /// JsonGenerator\#close is called (unless auto-closing + /// feature, + /// com.fasterxml.jackson.core.JsonGenerator.Feature\#AUTO_CLOSE_TARGET is enabled). + /// Using application needs to close it explicitly. + ///@since 2.1 + ///@param w Writer to use for writing JSON content + jni.JObject createGenerator2( + jni.JObject w, + ) { + return const jni.JObjectType() + .fromRef(_createGenerator2(reference, w.reference).object); + } + + static final _createGenerator3 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>("JsonFactory__createGenerator3") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); + + /// from: public com.fasterxml.jackson.core.JsonGenerator createGenerator(java.io.File f, com.fasterxml.jackson.core.JsonEncoding enc) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing JSON generator for writing JSON content + /// to specified file, overwriting contents it might have (or creating + /// it if such file does not yet exist). + /// Encoding to use must be specified, and needs to be one of available + /// types (as per JSON specification). + /// + /// Underlying stream __is owned__ by the generator constructed, + /// i.e. generator will handle closing of file when + /// JsonGenerator\#close is called. + ///@param f File to write contents to + ///@param enc Character encoding to use + ///@since 2.1 + jni.JObject createGenerator3( + jni.JObject f, + jni.JObject enc, + ) { + return const jni.JObjectType().fromRef( + _createGenerator3(reference, f.reference, enc.reference).object); + } + + static final _createGenerator4 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>("JsonFactory__createGenerator4") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); + + /// from: public com.fasterxml.jackson.core.JsonGenerator createGenerator(java.io.DataOutput out, com.fasterxml.jackson.core.JsonEncoding enc) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing generator for writing content using specified + /// DataOutput instance. + ///@since 2.8 + jni.JObject createGenerator4( + jni.JObject out, + jni.JObject enc, + ) { + return const jni.JObjectType().fromRef( + _createGenerator4(reference, out.reference, enc.reference).object); + } + + static final _createGenerator5 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__createGenerator5") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public com.fasterxml.jackson.core.JsonGenerator createGenerator(java.io.DataOutput out) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Convenience method for constructing generator that uses default + /// encoding of the format (UTF-8 for JSON and most other data formats). + /// + /// Note: there are formats that use fixed encoding (like most binary data formats). + ///@since 2.8 + jni.JObject createGenerator5( + jni.JObject out, + ) { + return const jni.JObjectType() + .fromRef(_createGenerator5(reference, out.reference).object); + } + + static final _createJsonParser = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__createJsonParser") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public com.fasterxml.jackson.core.JsonParser createJsonParser(java.io.File f) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing JSON parser instance to parse + /// contents of specified file. + /// + /// Encoding is auto-detected from contents according to JSON + /// specification recommended mechanism. Json specification + /// supports only UTF-8, UTF-16 and UTF-32 as valid encodings, + /// so auto-detection implemented only for this charsets. + /// For other charsets use \#createParser(java.io.Reader). + /// + /// + /// Underlying input stream (needed for reading contents) + /// will be __owned__ (and managed, i.e. closed as need be) by + /// the parser, since caller has no access to it. + ///@param f File that contains JSON content to parse + ///@return Parser constructed + ///@throws IOException if parser initialization fails due to I/O (read) problem + ///@throws JsonParseException if parser initialization fails due to content decoding problem + ///@deprecated Since 2.2, use \#createParser(File) instead. + jsonparser_.JsonParser createJsonParser( + jni.JObject f, + ) { + return const jsonparser_.$JsonParserType() + .fromRef(_createJsonParser(reference, f.reference).object); + } + + static final _createJsonParser1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__createJsonParser1") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public com.fasterxml.jackson.core.JsonParser createJsonParser(java.net.URL url) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing JSON parser instance to parse + /// contents of resource reference by given URL. + /// + /// Encoding is auto-detected from contents according to JSON + /// specification recommended mechanism. Json specification + /// supports only UTF-8, UTF-16 and UTF-32 as valid encodings, + /// so auto-detection implemented only for this charsets. + /// For other charsets use \#createParser(java.io.Reader). + /// + /// Underlying input stream (needed for reading contents) + /// will be __owned__ (and managed, i.e. closed as need be) by + /// the parser, since caller has no access to it. + ///@param url URL pointing to resource that contains JSON content to parse + ///@return Parser constructed + ///@throws IOException if parser initialization fails due to I/O (read) problem + ///@throws JsonParseException if parser initialization fails due to content decoding problem + ///@deprecated Since 2.2, use \#createParser(URL) instead. + jsonparser_.JsonParser createJsonParser1( + jni.JObject url, + ) { + return const jsonparser_.$JsonParserType() + .fromRef(_createJsonParser1(reference, url.reference).object); + } + + static final _createJsonParser2 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__createJsonParser2") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public com.fasterxml.jackson.core.JsonParser createJsonParser(java.io.InputStream in) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing JSON parser instance to parse + /// the contents accessed via specified input stream. + /// + /// The input stream will __not be owned__ by + /// the parser, it will still be managed (i.e. closed if + /// end-of-stream is reacher, or parser close method called) + /// if (and only if) com.fasterxml.jackson.core.JsonParser.Feature\#AUTO_CLOSE_SOURCE + /// is enabled. + /// + /// + /// Note: no encoding argument is taken since it can always be + /// auto-detected as suggested by JSON RFC. Json specification + /// supports only UTF-8, UTF-16 and UTF-32 as valid encodings, + /// so auto-detection implemented only for this charsets. + /// For other charsets use \#createParser(java.io.Reader). + ///@param in InputStream to use for reading JSON content to parse + ///@return Parser constructed + ///@throws IOException if parser initialization fails due to I/O (read) problem + ///@throws JsonParseException if parser initialization fails due to content decoding problem + ///@deprecated Since 2.2, use \#createParser(InputStream) instead. + jsonparser_.JsonParser createJsonParser2( + jni.JObject in0, + ) { + return const jsonparser_.$JsonParserType() + .fromRef(_createJsonParser2(reference, in0.reference).object); + } + + static final _createJsonParser3 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__createJsonParser3") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public com.fasterxml.jackson.core.JsonParser createJsonParser(java.io.Reader r) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing parser for parsing + /// the contents accessed via specified Reader. + /// + /// The read stream will __not be owned__ by + /// the parser, it will still be managed (i.e. closed if + /// end-of-stream is reacher, or parser close method called) + /// if (and only if) com.fasterxml.jackson.core.JsonParser.Feature\#AUTO_CLOSE_SOURCE + /// is enabled. + ///@param r Reader to use for reading JSON content to parse + ///@return Parser constructed + ///@throws IOException if parser initialization fails due to I/O (read) problem + ///@throws JsonParseException if parser initialization fails due to content decoding problem + ///@deprecated Since 2.2, use \#createParser(Reader) instead. + jsonparser_.JsonParser createJsonParser3( + jni.JObject r, + ) { + return const jsonparser_.$JsonParserType() + .fromRef(_createJsonParser3(reference, r.reference).object); + } + + static final _createJsonParser4 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__createJsonParser4") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public com.fasterxml.jackson.core.JsonParser createJsonParser(byte[] data) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing parser for parsing the contents of given byte array. + ///@param data Input content to parse + ///@return Parser constructed + ///@throws IOException if parser initialization fails due to I/O (read) problem + ///@throws JsonParseException if parser initialization fails due to content decoding problem + ///@deprecated Since 2.2, use \#createParser(byte[]) instead. + jsonparser_.JsonParser createJsonParser4( + jni.JArray data, + ) { + return const jsonparser_.$JsonParserType() + .fromRef(_createJsonParser4(reference, data.reference).object); + } + + static final _createJsonParser5 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Int32, + ffi.Int32)>>("JsonFactory__createJsonParser5") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer, int, int)>(); + + /// from: public com.fasterxml.jackson.core.JsonParser createJsonParser(byte[] data, int offset, int len) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing parser for parsing + /// the contents of given byte array. + ///@param data Buffer that contains data to parse + ///@param offset Offset of the first data byte within buffer + ///@param len Length of contents to parse within buffer + ///@return Parser constructed + ///@throws IOException if parser initialization fails due to I/O (read) problem + ///@throws JsonParseException if parser initialization fails due to content decoding problem + ///@deprecated Since 2.2, use \#createParser(byte[],int,int) instead. + jsonparser_.JsonParser createJsonParser5( + jni.JArray data, + int offset, + int len, + ) { + return const jsonparser_.$JsonParserType().fromRef( + _createJsonParser5(reference, data.reference, offset, len).object); + } + + static final _createJsonParser6 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__createJsonParser6") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public com.fasterxml.jackson.core.JsonParser createJsonParser(java.lang.String content) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing parser for parsing + /// contents of given String. + ///@param content Input content to parse + ///@return Parser constructed + ///@throws IOException if parser initialization fails due to I/O (read) problem + ///@throws JsonParseException if parser initialization fails due to content decoding problem + ///@deprecated Since 2.2, use \#createParser(String) instead. + jsonparser_.JsonParser createJsonParser6( + jni.JString content, + ) { + return const jsonparser_.$JsonParserType() + .fromRef(_createJsonParser6(reference, content.reference).object); + } + + static final _createJsonGenerator = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>("JsonFactory__createJsonGenerator") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); + + /// from: public com.fasterxml.jackson.core.JsonGenerator createJsonGenerator(java.io.OutputStream out, com.fasterxml.jackson.core.JsonEncoding enc) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing JSON generator for writing JSON content + /// using specified output stream. + /// Encoding to use must be specified, and needs to be one of available + /// types (as per JSON specification). + /// + /// Underlying stream __is NOT owned__ by the generator constructed, + /// so that generator will NOT close the output stream when + /// JsonGenerator\#close is called (unless auto-closing + /// feature, + /// com.fasterxml.jackson.core.JsonGenerator.Feature\#AUTO_CLOSE_TARGET + /// is enabled). + /// Using application needs to close it explicitly if this is the case. + /// + /// Note: there are formats that use fixed encoding (like most binary data formats) + /// and that ignore passed in encoding. + ///@param out OutputStream to use for writing JSON content + ///@param enc Character encoding to use + ///@return Generator constructed + ///@throws IOException if parser initialization fails due to I/O (write) problem + ///@deprecated Since 2.2, use \#createGenerator(OutputStream, JsonEncoding) instead. + jni.JObject createJsonGenerator( + jni.JObject out, + jni.JObject enc, + ) { + return const jni.JObjectType().fromRef( + _createJsonGenerator(reference, out.reference, enc.reference).object); + } + + static final _createJsonGenerator1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__createJsonGenerator1") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public com.fasterxml.jackson.core.JsonGenerator createJsonGenerator(java.io.Writer out) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing JSON generator for writing JSON content + /// using specified Writer. + /// + /// Underlying stream __is NOT owned__ by the generator constructed, + /// so that generator will NOT close the Reader when + /// JsonGenerator\#close is called (unless auto-closing + /// feature, + /// com.fasterxml.jackson.core.JsonGenerator.Feature\#AUTO_CLOSE_TARGET is enabled). + /// Using application needs to close it explicitly. + ///@param out Writer to use for writing JSON content + ///@return Generator constructed + ///@throws IOException if parser initialization fails due to I/O (write) problem + ///@deprecated Since 2.2, use \#createGenerator(Writer) instead. + jni.JObject createJsonGenerator1( + jni.JObject out, + ) { + return const jni.JObjectType() + .fromRef(_createJsonGenerator1(reference, out.reference).object); + } + + static final _createJsonGenerator2 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonFactory__createJsonGenerator2") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public com.fasterxml.jackson.core.JsonGenerator createJsonGenerator(java.io.OutputStream out) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Convenience method for constructing generator that uses default + /// encoding of the format (UTF-8 for JSON and most other data formats). + /// + /// Note: there are formats that use fixed encoding (like most binary data formats). + ///@param out OutputStream to use for writing JSON content + ///@return Generator constructed + ///@throws IOException if parser initialization fails due to I/O (write) problem + ///@deprecated Since 2.2, use \#createGenerator(OutputStream) instead. + jni.JObject createJsonGenerator2( + jni.JObject out, + ) { + return const jni.JObjectType() + .fromRef(_createJsonGenerator2(reference, out.reference).object); + } +} + +final class $JsonFactoryType extends jni.JObjType { + const $JsonFactoryType(); + + @override + String get signature => r"Lcom/fasterxml/jackson/core/JsonFactory;"; + + @override + JsonFactory fromRef(jni.JObjectPtr ref) => JsonFactory.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($JsonFactoryType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($JsonFactoryType) && other is $JsonFactoryType; + } +} + +/// from: com.fasterxml.jackson.core.JsonFactory$Feature +/// +/// Enumeration that defines all on/off features that can only be +/// changed for JsonFactory. +class JsonFactory_Feature extends jni.JObject { + @override + late final jni.JObjType $type = type; + + JsonFactory_Feature.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $JsonFactory_FeatureType(); + static final _values = + jniLookup>( + "JsonFactory_Feature__values") + .asFunction(); + + /// from: static public com.fasterxml.jackson.core.JsonFactory.Feature[] values() + /// The returned object must be released after use, by calling the [release] method. + static jni.JArray values() { + return const jni.JArrayType($JsonFactory_FeatureType()) + .fromRef(_values().object); + } + + static final _valueOf = jniLookup< + ffi + .NativeFunction)>>( + "JsonFactory_Feature__valueOf") + .asFunction)>(); + + /// from: static public com.fasterxml.jackson.core.JsonFactory.Feature valueOf(java.lang.String name) + /// The returned object must be released after use, by calling the [release] method. + static JsonFactory_Feature valueOf( + jni.JString name, + ) { + return const $JsonFactory_FeatureType() + .fromRef(_valueOf(name.reference).object); + } + + static final _collectDefaults = + jniLookup>( + "JsonFactory_Feature__collectDefaults") + .asFunction(); + + /// from: static public int collectDefaults() + /// + /// Method that calculates bit set (flags) of all features that + /// are enabled by default. + ///@return Bit field of features enabled by default + static int collectDefaults() { + return _collectDefaults().integer; + } + + static final _enabledByDefault = jniLookup< + ffi + .NativeFunction)>>( + "JsonFactory_Feature__enabledByDefault") + .asFunction)>(); + + /// from: public boolean enabledByDefault() + bool enabledByDefault() { + return _enabledByDefault(reference).boolean; + } + + static final _enabledIn = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Int32)>>("JsonFactory_Feature__enabledIn") + .asFunction, int)>(); + + /// from: public boolean enabledIn(int flags) + bool enabledIn( + int flags, + ) { + return _enabledIn(reference, flags).boolean; + } + + static final _getMask = jniLookup< + ffi + .NativeFunction)>>( + "JsonFactory_Feature__getMask") + .asFunction)>(); + + /// from: public int getMask() + int getMask() { + return _getMask(reference).integer; + } +} + +final class $JsonFactory_FeatureType extends jni.JObjType { + const $JsonFactory_FeatureType(); + + @override + String get signature => r"Lcom/fasterxml/jackson/core/JsonFactory$Feature;"; + + @override + JsonFactory_Feature fromRef(jni.JObjectPtr ref) => + JsonFactory_Feature.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($JsonFactory_FeatureType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($JsonFactory_FeatureType) && + other is $JsonFactory_FeatureType; + } +} diff --git a/pkgs/jnigen/test/jackson_core_test/third_party/c_based/dart_bindings/com/fasterxml/jackson/core/JsonParser.dart b/pkgs/jnigen/test/jackson_core_test/third_party/c_based/dart_bindings/com/fasterxml/jackson/core/JsonParser.dart new file mode 100644 index 000000000..5775da71b --- /dev/null +++ b/pkgs/jnigen/test/jackson_core_test/third_party/c_based/dart_bindings/com/fasterxml/jackson/core/JsonParser.dart @@ -0,0 +1,2846 @@ +// Generated from jackson-core which is licensed under the Apache License 2.0. +// The following copyright from the original authors applies. +// See https://github.com/FasterXML/jackson-core/blob/2.14/LICENSE +// +// Copyright (c) 2007 - The Jackson Project Authors +// Licensed under the Apache License, Version 2.0 (the "License") +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Autogenerated by jnigen. DO NOT EDIT! + +// ignore_for_file: annotate_overrides +// ignore_for_file: camel_case_extensions +// ignore_for_file: camel_case_types +// ignore_for_file: constant_identifier_names +// ignore_for_file: file_names +// ignore_for_file: lines_longer_than_80_chars +// ignore_for_file: no_leading_underscores_for_local_identifiers +// ignore_for_file: non_constant_identifier_names +// ignore_for_file: overridden_fields +// ignore_for_file: unnecessary_cast +// ignore_for_file: unused_element +// ignore_for_file: unused_field +// ignore_for_file: unused_import +// ignore_for_file: unused_local_variable +// ignore_for_file: unused_shown_name + +import "dart:isolate" show ReceivePort; +import "dart:ffi" as ffi; +import "package:jni/internal_helpers_for_jnigen.dart"; +import "package:jni/jni.dart" as jni; + +import "JsonToken.dart" as jsontoken_; +import "../../../../_init.dart"; + +/// from: com.fasterxml.jackson.core.JsonParser +/// +/// Base class that defines public API for reading JSON content. +/// Instances are created using factory methods of +/// a JsonFactory instance. +///@author Tatu Saloranta +class JsonParser extends jni.JObject { + @override + late final jni.JObjType $type = type; + + JsonParser.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $JsonParserType(); + static final _get_DEFAULT_READ_CAPABILITIES = + jniLookup>( + "get_JsonParser__DEFAULT_READ_CAPABILITIES") + .asFunction(); + + /// from: static protected final com.fasterxml.jackson.core.util.JacksonFeatureSet DEFAULT_READ_CAPABILITIES + /// The returned object must be released after use, by calling the [release] method. + /// + /// Default set of StreamReadCapabilityies that may be used as + /// basis for format-specific readers (or as bogus instance if non-null + /// set needs to be passed). + ///@since 2.12 + static jni.JObject get DEFAULT_READ_CAPABILITIES => + const jni.JObjectType().fromRef(_get_DEFAULT_READ_CAPABILITIES().object); + + static final _new0 = jniLookup>( + "JsonParser__new0") + .asFunction(); + + /// from: protected void () + /// The returned object must be released after use, by calling the [release] method. + factory JsonParser() { + return JsonParser.fromRef(_new0().object); + } + + static final _new1 = + jniLookup>( + "JsonParser__new1") + .asFunction(); + + /// from: protected void (int features) + /// The returned object must be released after use, by calling the [release] method. + factory JsonParser.new1( + int features, + ) { + return JsonParser.fromRef(_new1(features).object); + } + + static final _getCodec = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getCodec") + .asFunction)>(); + + /// from: public abstract com.fasterxml.jackson.core.ObjectCodec getCodec() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Accessor for ObjectCodec associated with this + /// parser, if any. Codec is used by \#readValueAs(Class) + /// method (and its variants). + ///@return Codec assigned to this parser, if any; {@code null} if none + jni.JObject getCodec() { + return const jni.JObjectType().fromRef(_getCodec(reference).object); + } + + static final _setCodec = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonParser__setCodec") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public abstract void setCodec(com.fasterxml.jackson.core.ObjectCodec oc) + /// + /// Setter that allows defining ObjectCodec associated with this + /// parser, if any. Codec is used by \#readValueAs(Class) + /// method (and its variants). + ///@param oc Codec to assign, if any; {@code null} if none + void setCodec( + jni.JObject oc, + ) { + return _setCodec(reference, oc.reference).check(); + } + + static final _getInputSource = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getInputSource") + .asFunction)>(); + + /// from: public java.lang.Object getInputSource() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that can be used to get access to object that is used + /// to access input being parsed; this is usually either + /// InputStream or Reader, depending on what + /// parser was constructed with. + /// Note that returned value may be null in some cases; including + /// case where parser implementation does not want to exposed raw + /// source to caller. + /// In cases where input has been decorated, object returned here + /// is the decorated version; this allows some level of interaction + /// between users of parser and decorator object. + /// + /// In general use of this accessor should be considered as + /// "last effort", i.e. only used if no other mechanism is applicable. + ///@return Input source this parser was configured with + jni.JObject getInputSource() { + return const jni.JObjectType().fromRef(_getInputSource(reference).object); + } + + static final _setRequestPayloadOnError = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>>( + "JsonParser__setRequestPayloadOnError") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void setRequestPayloadOnError(com.fasterxml.jackson.core.util.RequestPayload payload) + /// + /// Sets the payload to be passed if JsonParseException is thrown. + ///@param payload Payload to pass + ///@since 2.8 + void setRequestPayloadOnError( + jni.JObject payload, + ) { + return _setRequestPayloadOnError(reference, payload.reference).check(); + } + + static final _setRequestPayloadOnError1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer, ffi.Pointer)>>( + "JsonParser__setRequestPayloadOnError1") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); + + /// from: public void setRequestPayloadOnError(byte[] payload, java.lang.String charset) + /// + /// Sets the byte[] request payload and the charset + ///@param payload Payload to pass + ///@param charset Character encoding for (lazily) decoding payload + ///@since 2.8 + void setRequestPayloadOnError1( + jni.JArray payload, + jni.JString charset, + ) { + return _setRequestPayloadOnError1( + reference, payload.reference, charset.reference) + .check(); + } + + static final _setRequestPayloadOnError2 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>>( + "JsonParser__setRequestPayloadOnError2") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void setRequestPayloadOnError(java.lang.String payload) + /// + /// Sets the String request payload + ///@param payload Payload to pass + ///@since 2.8 + void setRequestPayloadOnError2( + jni.JString payload, + ) { + return _setRequestPayloadOnError2(reference, payload.reference).check(); + } + + static final _setSchema = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonParser__setSchema") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void setSchema(com.fasterxml.jackson.core.FormatSchema schema) + /// + /// Method to call to make this parser use specified schema. Method must + /// be called before trying to parse any content, right after parser instance + /// has been created. + /// Note that not all parsers support schemas; and those that do usually only + /// accept specific types of schemas: ones defined for data format parser can read. + /// + /// If parser does not support specified schema, UnsupportedOperationException + /// is thrown. + ///@param schema Schema to use + ///@throws UnsupportedOperationException if parser does not support schema + void setSchema( + jni.JObject schema, + ) { + return _setSchema(reference, schema.reference).check(); + } + + static final _getSchema = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getSchema") + .asFunction)>(); + + /// from: public com.fasterxml.jackson.core.FormatSchema getSchema() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for accessing Schema that this parser uses, if any. + /// Default implementation returns null. + ///@return Schema in use by this parser, if any; {@code null} if none + ///@since 2.1 + jni.JObject getSchema() { + return const jni.JObjectType().fromRef(_getSchema(reference).object); + } + + static final _canUseSchema = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonParser__canUseSchema") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public boolean canUseSchema(com.fasterxml.jackson.core.FormatSchema schema) + /// + /// Method that can be used to verify that given schema can be used with + /// this parser (using \#setSchema). + ///@param schema Schema to check + ///@return True if this parser can use given schema; false if not + bool canUseSchema( + jni.JObject schema, + ) { + return _canUseSchema(reference, schema.reference).boolean; + } + + static final _requiresCustomCodec = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__requiresCustomCodec") + .asFunction)>(); + + /// from: public boolean requiresCustomCodec() + /// + /// Method that can be called to determine if a custom + /// ObjectCodec is needed for binding data parsed + /// using JsonParser constructed by this factory + /// (which typically also implies the same for serialization + /// with JsonGenerator). + ///@return True if format-specific codec is needed with this parser; false if a general + /// ObjectCodec is enough + ///@since 2.1 + bool requiresCustomCodec() { + return _requiresCustomCodec(reference).boolean; + } + + static final _canParseAsync = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__canParseAsync") + .asFunction)>(); + + /// from: public boolean canParseAsync() + /// + /// Method that can be called to determine if this parser instance + /// uses non-blocking ("asynchronous") input access for decoding or not. + /// Access mode is determined by earlier calls via JsonFactory; + /// it may not be changed after construction. + /// + /// If non-blocking decoding is (@code true}, it is possible to call + /// \#getNonBlockingInputFeeder() to obtain object to use + /// for feeding input; otherwise (false returned) + /// input is read by blocking + ///@return True if this is a non-blocking ("asynchronous") parser + ///@since 2.9 + bool canParseAsync() { + return _canParseAsync(reference).boolean; + } + + static final _getNonBlockingInputFeeder = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getNonBlockingInputFeeder") + .asFunction)>(); + + /// from: public com.fasterxml.jackson.core.async.NonBlockingInputFeeder getNonBlockingInputFeeder() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that will either return a feeder instance (if parser uses + /// non-blocking, aka asynchronous access); or null for + /// parsers that use blocking I/O. + ///@return Input feeder to use with non-blocking (async) parsing + ///@since 2.9 + jni.JObject getNonBlockingInputFeeder() { + return const jni.JObjectType() + .fromRef(_getNonBlockingInputFeeder(reference).object); + } + + static final _getReadCapabilities = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getReadCapabilities") + .asFunction)>(); + + /// from: public com.fasterxml.jackson.core.util.JacksonFeatureSet getReadCapabilities() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Accessor for getting metadata on capabilities of this parser, based on + /// underlying data format being read (directly or indirectly). + ///@return Set of read capabilities for content to read via this parser + ///@since 2.12 + jni.JObject getReadCapabilities() { + return const jni.JObjectType() + .fromRef(_getReadCapabilities(reference).object); + } + + static final _version = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__version") + .asFunction)>(); + + /// from: public abstract com.fasterxml.jackson.core.Version version() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Accessor for getting version of the core package, given a parser instance. + /// Left for sub-classes to implement. + ///@return Version of this generator (derived from version declared for + /// {@code jackson-core} jar that contains the class + jni.JObject version() { + return const jni.JObjectType().fromRef(_version(reference).object); + } + + static final _close = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__close") + .asFunction)>(); + + /// from: public abstract void close() + /// + /// Closes the parser so that no further iteration or data access + /// can be made; will also close the underlying input source + /// if parser either __owns__ the input source, or feature + /// Feature\#AUTO_CLOSE_SOURCE is enabled. + /// Whether parser owns the input source depends on factory + /// method that was used to construct instance (so check + /// com.fasterxml.jackson.core.JsonFactory for details, + /// but the general + /// idea is that if caller passes in closable resource (such + /// as InputStream or Reader) parser does NOT + /// own the source; but if it passes a reference (such as + /// java.io.File or java.net.URL and creates + /// stream or reader it does own them. + ///@throws IOException if there is either an underlying I/O problem + void close() { + return _close(reference).check(); + } + + static final _isClosed = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__isClosed") + .asFunction)>(); + + /// from: public abstract boolean isClosed() + /// + /// Method that can be called to determine whether this parser + /// is closed or not. If it is closed, no new tokens can be + /// retrieved by calling \#nextToken (and the underlying + /// stream may be closed). Closing may be due to an explicit + /// call to \#close or because parser has encountered + /// end of input. + ///@return {@code True} if this parser instance has been closed + bool isClosed() { + return _isClosed(reference).boolean; + } + + static final _getParsingContext = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getParsingContext") + .asFunction)>(); + + /// from: public abstract com.fasterxml.jackson.core.JsonStreamContext getParsingContext() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that can be used to access current parsing context reader + /// is in. There are 3 different types: root, array and object contexts, + /// with slightly different available information. Contexts are + /// hierarchically nested, and can be used for example for figuring + /// out part of the input document that correspond to specific + /// array or object (for highlighting purposes, or error reporting). + /// Contexts can also be used for simple xpath-like matching of + /// input, if so desired. + ///@return Stream input context (JsonStreamContext) associated with this parser + jni.JObject getParsingContext() { + return const jni.JObjectType() + .fromRef(_getParsingContext(reference).object); + } + + static final _currentLocation = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__currentLocation") + .asFunction)>(); + + /// from: public com.fasterxml.jackson.core.JsonLocation currentLocation() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that returns location of the last processed input unit (character + /// or byte) from the input; + /// usually for error reporting purposes. + /// + /// Note that the location is not guaranteed to be accurate (although most + /// implementation will try their best): some implementations may only + /// report specific boundary locations (start or end locations of tokens) + /// and others only return JsonLocation\#NA due to not having access + /// to input location information (when delegating actual decoding work + /// to other library) + ///@return Location of the last processed input unit (byte or character) + ///@since 2.13 + jni.JObject currentLocation() { + return const jni.JObjectType().fromRef(_currentLocation(reference).object); + } + + static final _currentTokenLocation = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__currentTokenLocation") + .asFunction)>(); + + /// from: public com.fasterxml.jackson.core.JsonLocation currentTokenLocation() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that return the __starting__ location of the current + /// (most recently returned) + /// token; that is, the position of the first input unit (character or byte) from input + /// that starts the current token. + /// + /// Note that the location is not guaranteed to be accurate (although most + /// implementation will try their best): some implementations may only + /// return JsonLocation\#NA due to not having access + /// to input location information (when delegating actual decoding work + /// to other library) + ///@return Starting location of the token parser currently points to + ///@since 2.13 (will eventually replace \#getTokenLocation) + jni.JObject currentTokenLocation() { + return const jni.JObjectType() + .fromRef(_currentTokenLocation(reference).object); + } + + static final _getCurrentLocation = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getCurrentLocation") + .asFunction)>(); + + /// from: public abstract com.fasterxml.jackson.core.JsonLocation getCurrentLocation() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Alias for \#currentLocation(), to be deprecated in later + /// Jackson 2.x versions (and removed from Jackson 3.0). + ///@return Location of the last processed input unit (byte or character) + jni.JObject getCurrentLocation() { + return const jni.JObjectType() + .fromRef(_getCurrentLocation(reference).object); + } + + static final _getTokenLocation = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getTokenLocation") + .asFunction)>(); + + /// from: public abstract com.fasterxml.jackson.core.JsonLocation getTokenLocation() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Alias for \#currentTokenLocation(), to be deprecated in later + /// Jackson 2.x versions (and removed from Jackson 3.0). + ///@return Starting location of the token parser currently points to + jni.JObject getTokenLocation() { + return const jni.JObjectType().fromRef(_getTokenLocation(reference).object); + } + + static final _currentValue = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__currentValue") + .asFunction)>(); + + /// from: public java.lang.Object currentValue() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Helper method, usually equivalent to: + /// + /// getParsingContext().getCurrentValue(); + /// + /// + /// Note that "current value" is NOT populated (or used) by Streaming parser; + /// it is only used by higher-level data-binding functionality. + /// The reason it is included here is that it can be stored and accessed hierarchically, + /// and gets passed through data-binding. + ///@return "Current value" associated with the current input context (state) of this parser + ///@since 2.13 (added as replacement for older \#getCurrentValue() + jni.JObject currentValue() { + return const jni.JObjectType().fromRef(_currentValue(reference).object); + } + + static final _assignCurrentValue = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonParser__assignCurrentValue") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void assignCurrentValue(java.lang.Object v) + /// + /// Helper method, usually equivalent to: + /// + /// getParsingContext().setCurrentValue(v); + /// + ///@param v Current value to assign for the current input context of this parser + ///@since 2.13 (added as replacement for older \#setCurrentValue + void assignCurrentValue( + jni.JObject v, + ) { + return _assignCurrentValue(reference, v.reference).check(); + } + + static final _getCurrentValue = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getCurrentValue") + .asFunction)>(); + + /// from: public java.lang.Object getCurrentValue() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Alias for \#currentValue(), to be deprecated in later + /// Jackson 2.x versions (and removed from Jackson 3.0). + ///@return Location of the last processed input unit (byte or character) + jni.JObject getCurrentValue() { + return const jni.JObjectType().fromRef(_getCurrentValue(reference).object); + } + + static final _setCurrentValue = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonParser__setCurrentValue") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void setCurrentValue(java.lang.Object v) + /// + /// Alias for \#assignCurrentValue, to be deprecated in later + /// Jackson 2.x versions (and removed from Jackson 3.0). + ///@param v Current value to assign for the current input context of this parser + void setCurrentValue( + jni.JObject v, + ) { + return _setCurrentValue(reference, v.reference).check(); + } + + static final _releaseBuffered = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonParser__releaseBuffered") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public int releaseBuffered(java.io.OutputStream out) + /// + /// Method that can be called to push back any content that + /// has been read but not consumed by the parser. This is usually + /// done after reading all content of interest using parser. + /// Content is released by writing it to given stream if possible; + /// if underlying input is byte-based it can released, if not (char-based) + /// it can not. + ///@param out OutputStream to which buffered, undecoded content is written to + ///@return -1 if the underlying content source is not byte based + /// (that is, input can not be sent to OutputStream; + /// otherwise number of bytes released (0 if there was nothing to release) + ///@throws IOException if write to stream threw exception + int releaseBuffered( + jni.JObject out, + ) { + return _releaseBuffered(reference, out.reference).integer; + } + + static final _releaseBuffered1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonParser__releaseBuffered1") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public int releaseBuffered(java.io.Writer w) + /// + /// Method that can be called to push back any content that + /// has been read but not consumed by the parser. + /// This is usually + /// done after reading all content of interest using parser. + /// Content is released by writing it to given writer if possible; + /// if underlying input is char-based it can released, if not (byte-based) + /// it can not. + ///@param w Writer to which buffered but unprocessed content is written to + ///@return -1 if the underlying content source is not char-based + /// (that is, input can not be sent to Writer; + /// otherwise number of chars released (0 if there was nothing to release) + ///@throws IOException if write using Writer threw exception + int releaseBuffered1( + jni.JObject w, + ) { + return _releaseBuffered1(reference, w.reference).integer; + } + + static final _enable = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonParser__enable") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public com.fasterxml.jackson.core.JsonParser enable(com.fasterxml.jackson.core.JsonParser.Feature f) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for enabling specified parser feature + /// (check Feature for list of features) + ///@param f Feature to enable + ///@return This parser, to allow call chaining + JsonParser enable( + JsonParser_Feature f, + ) { + return const $JsonParserType() + .fromRef(_enable(reference, f.reference).object); + } + + static final _disable = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonParser__disable") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public com.fasterxml.jackson.core.JsonParser disable(com.fasterxml.jackson.core.JsonParser.Feature f) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for disabling specified feature + /// (check Feature for list of features) + ///@param f Feature to disable + ///@return This parser, to allow call chaining + JsonParser disable( + JsonParser_Feature f, + ) { + return const $JsonParserType() + .fromRef(_disable(reference, f.reference).object); + } + + static final _configure = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer, ffi.Uint8)>>("JsonParser__configure") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer, int)>(); + + /// from: public com.fasterxml.jackson.core.JsonParser configure(com.fasterxml.jackson.core.JsonParser.Feature f, boolean state) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for enabling or disabling specified feature + /// (check Feature for list of features) + ///@param f Feature to enable or disable + ///@param state Whether to enable feature ({@code true}) or disable ({@code false}) + ///@return This parser, to allow call chaining + JsonParser configure( + JsonParser_Feature f, + bool state, + ) { + return const $JsonParserType() + .fromRef(_configure(reference, f.reference, state ? 1 : 0).object); + } + + static final _isEnabled = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonParser__isEnabled") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public boolean isEnabled(com.fasterxml.jackson.core.JsonParser.Feature f) + /// + /// Method for checking whether specified Feature is enabled. + ///@param f Feature to check + ///@return {@code True} if feature is enabled; {@code false} otherwise + bool isEnabled( + JsonParser_Feature f, + ) { + return _isEnabled(reference, f.reference).boolean; + } + + static final _isEnabled1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonParser__isEnabled1") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public boolean isEnabled(com.fasterxml.jackson.core.StreamReadFeature f) + /// + /// Method for checking whether specified Feature is enabled. + ///@param f Feature to check + ///@return {@code True} if feature is enabled; {@code false} otherwise + ///@since 2.10 + bool isEnabled1( + jni.JObject f, + ) { + return _isEnabled1(reference, f.reference).boolean; + } + + static final _getFeatureMask = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getFeatureMask") + .asFunction)>(); + + /// from: public int getFeatureMask() + /// + /// Bulk access method for getting state of all standard Features. + ///@return Bit mask that defines current states of all standard Features. + ///@since 2.3 + int getFeatureMask() { + return _getFeatureMask(reference).integer; + } + + static final _setFeatureMask = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Int32)>>("JsonParser__setFeatureMask") + .asFunction, int)>(); + + /// from: public com.fasterxml.jackson.core.JsonParser setFeatureMask(int mask) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Bulk set method for (re)setting states of all standard Features + ///@param mask Bit mask that defines set of features to enable + ///@return This parser, to allow call chaining + ///@since 2.3 + ///@deprecated Since 2.7, use \#overrideStdFeatures(int, int) instead + JsonParser setFeatureMask( + int mask, + ) { + return const $JsonParserType() + .fromRef(_setFeatureMask(reference, mask).object); + } + + static final _overrideStdFeatures = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, ffi.Int32, + ffi.Int32)>>("JsonParser__overrideStdFeatures") + .asFunction, int, int)>(); + + /// from: public com.fasterxml.jackson.core.JsonParser overrideStdFeatures(int values, int mask) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Bulk set method for (re)setting states of features specified by mask. + /// Functionally equivalent to + /// + /// int oldState = getFeatureMask(); + /// int newState = (oldState & ~mask) | (values & mask); + /// setFeatureMask(newState); + /// + /// but preferred as this lets caller more efficiently specify actual changes made. + ///@param values Bit mask of set/clear state for features to change + ///@param mask Bit mask of features to change + ///@return This parser, to allow call chaining + ///@since 2.6 + JsonParser overrideStdFeatures( + int values, + int mask, + ) { + return const $JsonParserType() + .fromRef(_overrideStdFeatures(reference, values, mask).object); + } + + static final _getFormatFeatures = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getFormatFeatures") + .asFunction)>(); + + /// from: public int getFormatFeatures() + /// + /// Bulk access method for getting state of all FormatFeatures, format-specific + /// on/off configuration settings. + ///@return Bit mask that defines current states of all standard FormatFeatures. + ///@since 2.6 + int getFormatFeatures() { + return _getFormatFeatures(reference).integer; + } + + static final _overrideFormatFeatures = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, ffi.Int32, + ffi.Int32)>>("JsonParser__overrideFormatFeatures") + .asFunction, int, int)>(); + + /// from: public com.fasterxml.jackson.core.JsonParser overrideFormatFeatures(int values, int mask) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Bulk set method for (re)setting states of FormatFeatures, + /// by specifying values (set / clear) along with a mask, to determine + /// which features to change, if any. + /// + /// Default implementation will simply throw an exception to indicate that + /// the parser implementation does not support any FormatFeatures. + ///@param values Bit mask of set/clear state for features to change + ///@param mask Bit mask of features to change + ///@return This parser, to allow call chaining + ///@since 2.6 + JsonParser overrideFormatFeatures( + int values, + int mask, + ) { + return const $JsonParserType() + .fromRef(_overrideFormatFeatures(reference, values, mask).object); + } + + static final _nextToken = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__nextToken") + .asFunction)>(); + + /// from: public abstract com.fasterxml.jackson.core.JsonToken nextToken() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Main iteration method, which will advance stream enough + /// to determine type of the next token, if any. If none + /// remaining (stream has no content other than possible + /// white space before ending), null will be returned. + ///@return Next token from the stream, if any found, or null + /// to indicate end-of-input + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + jsontoken_.JsonToken nextToken() { + return const jsontoken_.$JsonTokenType() + .fromRef(_nextToken(reference).object); + } + + static final _nextValue = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__nextValue") + .asFunction)>(); + + /// from: public abstract com.fasterxml.jackson.core.JsonToken nextValue() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Iteration method that will advance stream enough + /// to determine type of the next token that is a value type + /// (including JSON Array and Object start/end markers). + /// Or put another way, nextToken() will be called once, + /// and if JsonToken\#FIELD_NAME is returned, another + /// time to get the value for the field. + /// Method is most useful for iterating over value entries + /// of JSON objects; field name will still be available + /// by calling \#getCurrentName when parser points to + /// the value. + ///@return Next non-field-name token from the stream, if any found, + /// or null to indicate end-of-input (or, for non-blocking + /// parsers, JsonToken\#NOT_AVAILABLE if no tokens were + /// available yet) + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + jsontoken_.JsonToken nextValue() { + return const jsontoken_.$JsonTokenType() + .fromRef(_nextValue(reference).object); + } + + static final _nextFieldName = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonParser__nextFieldName") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public boolean nextFieldName(com.fasterxml.jackson.core.SerializableString str) + /// + /// Method that fetches next token (as if calling \#nextToken) and + /// verifies whether it is JsonToken\#FIELD_NAME with specified name + /// and returns result of that comparison. + /// It is functionally equivalent to: + ///
+  ///  return (nextToken() == JsonToken.FIELD_NAME) && str.getValue().equals(getCurrentName());
+  ///
+ /// but may be faster for parser to verify, and can therefore be used if caller + /// expects to get such a property name from input next. + ///@param str Property name to compare next token to (if next token is + /// JsonToken.FIELD_NAME) + ///@return {@code True} if parser advanced to {@code JsonToken.FIELD_NAME} with + /// specified name; {@code false} otherwise (different token or non-matching name) + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + bool nextFieldName( + jni.JObject str, + ) { + return _nextFieldName(reference, str.reference).boolean; + } + + static final _nextFieldName1 = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__nextFieldName1") + .asFunction)>(); + + /// from: public java.lang.String nextFieldName() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that fetches next token (as if calling \#nextToken) and + /// verifies whether it is JsonToken\#FIELD_NAME; if it is, + /// returns same as \#getCurrentName(), otherwise null. + ///@return Name of the the {@code JsonToken.FIELD_NAME} parser advanced to, if any; + /// {@code null} if next token is of some other type + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + ///@since 2.5 + jni.JString nextFieldName1() { + return const jni.JStringType().fromRef(_nextFieldName1(reference).object); + } + + static final _nextTextValue = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__nextTextValue") + .asFunction)>(); + + /// from: public java.lang.String nextTextValue() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that fetches next token (as if calling \#nextToken) and + /// if it is JsonToken\#VALUE_STRING returns contained String value; + /// otherwise returns null. + /// It is functionally equivalent to: + ///
+  ///  return (nextToken() == JsonToken.VALUE_STRING) ? getText() : null;
+  ///
+ /// but may be faster for parser to process, and can therefore be used if caller + /// expects to get a String value next from input. + ///@return Text value of the {@code JsonToken.VALUE_STRING} token parser advanced + /// to; or {@code null} if next token is of some other type + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + jni.JString nextTextValue() { + return const jni.JStringType().fromRef(_nextTextValue(reference).object); + } + + static final _nextIntValue = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Int32)>>("JsonParser__nextIntValue") + .asFunction, int)>(); + + /// from: public int nextIntValue(int defaultValue) + /// + /// Method that fetches next token (as if calling \#nextToken) and + /// if it is JsonToken\#VALUE_NUMBER_INT returns 32-bit int value; + /// otherwise returns specified default value + /// It is functionally equivalent to: + ///
+  ///  return (nextToken() == JsonToken.VALUE_NUMBER_INT) ? getIntValue() : defaultValue;
+  ///
+ /// but may be faster for parser to process, and can therefore be used if caller + /// expects to get an int value next from input. + /// + /// NOTE: value checks are performed similar to \#getIntValue() + ///@param defaultValue Value to return if next token is NOT of type {@code JsonToken.VALUE_NUMBER_INT} + ///@return Integer ({@code int}) value of the {@code JsonToken.VALUE_NUMBER_INT} token parser advanced + /// to; or {@code defaultValue} if next token is of some other type + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + ///@throws InputCoercionException if integer number does not fit in Java {@code int} + int nextIntValue( + int defaultValue, + ) { + return _nextIntValue(reference, defaultValue).integer; + } + + static final _nextLongValue = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Int64)>>("JsonParser__nextLongValue") + .asFunction, int)>(); + + /// from: public long nextLongValue(long defaultValue) + /// + /// Method that fetches next token (as if calling \#nextToken) and + /// if it is JsonToken\#VALUE_NUMBER_INT returns 64-bit long value; + /// otherwise returns specified default value + /// It is functionally equivalent to: + ///
+  ///  return (nextToken() == JsonToken.VALUE_NUMBER_INT) ? getLongValue() : defaultValue;
+  ///
+ /// but may be faster for parser to process, and can therefore be used if caller + /// expects to get a long value next from input. + /// + /// NOTE: value checks are performed similar to \#getLongValue() + ///@param defaultValue Value to return if next token is NOT of type {@code JsonToken.VALUE_NUMBER_INT} + ///@return {@code long} value of the {@code JsonToken.VALUE_NUMBER_INT} token parser advanced + /// to; or {@code defaultValue} if next token is of some other type + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + ///@throws InputCoercionException if integer number does not fit in Java {@code long} + int nextLongValue( + int defaultValue, + ) { + return _nextLongValue(reference, defaultValue).long; + } + + static final _nextBooleanValue = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__nextBooleanValue") + .asFunction)>(); + + /// from: public java.lang.Boolean nextBooleanValue() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that fetches next token (as if calling \#nextToken) and + /// if it is JsonToken\#VALUE_TRUE or JsonToken\#VALUE_FALSE + /// returns matching Boolean value; otherwise return null. + /// It is functionally equivalent to: + ///
+  ///  JsonToken t = nextToken();
+  ///  if (t == JsonToken.VALUE_TRUE) return Boolean.TRUE;
+  ///  if (t == JsonToken.VALUE_FALSE) return Boolean.FALSE;
+  ///  return null;
+  ///
+ /// but may be faster for parser to process, and can therefore be used if caller + /// expects to get a Boolean value next from input. + ///@return {@code Boolean} value of the {@code JsonToken.VALUE_TRUE} or {@code JsonToken.VALUE_FALSE} + /// token parser advanced to; or {@code null} if next token is of some other type + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + jni.JBoolean nextBooleanValue() { + return const jni.JBooleanType() + .fromRef(_nextBooleanValue(reference).object); + } + + static final _skipChildren = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__skipChildren") + .asFunction)>(); + + /// from: public abstract com.fasterxml.jackson.core.JsonParser skipChildren() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that will skip all child tokens of an array or + /// object token that the parser currently points to, + /// iff stream points to + /// JsonToken\#START_OBJECT or JsonToken\#START_ARRAY. + /// If not, it will do nothing. + /// After skipping, stream will point to __matching__ + /// JsonToken\#END_OBJECT or JsonToken\#END_ARRAY + /// (possibly skipping nested pairs of START/END OBJECT/ARRAY tokens + /// as well as value tokens). + /// The idea is that after calling this method, application + /// will call \#nextToken to point to the next + /// available token, if any. + ///@return This parser, to allow call chaining + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + JsonParser skipChildren() { + return const $JsonParserType().fromRef(_skipChildren(reference).object); + } + + static final _finishToken = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__finishToken") + .asFunction)>(); + + /// from: public void finishToken() + /// + /// Method that may be used to force full handling of the current token + /// so that even if lazy processing is enabled, the whole contents are + /// read for possible retrieval. This is usually used to ensure that + /// the token end location is available, as well as token contents + /// (similar to what calling, say \#getTextCharacters(), would + /// achieve). + /// + /// Note that for many dataformat implementations this method + /// will not do anything; this is the default implementation unless + /// overridden by sub-classes. + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + ///@since 2.8 + void finishToken() { + return _finishToken(reference).check(); + } + + static final _currentToken = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__currentToken") + .asFunction)>(); + + /// from: public com.fasterxml.jackson.core.JsonToken currentToken() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Accessor to find which token parser currently points to, if any; + /// null will be returned if none. + /// If return value is non-null, data associated with the token + /// is available via other accessor methods. + ///@return Type of the token this parser currently points to, + /// if any: null before any tokens have been read, and + /// after end-of-input has been encountered, as well as + /// if the current token has been explicitly cleared. + ///@since 2.8 + jsontoken_.JsonToken currentToken() { + return const jsontoken_.$JsonTokenType() + .fromRef(_currentToken(reference).object); + } + + static final _currentTokenId = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__currentTokenId") + .asFunction)>(); + + /// from: public int currentTokenId() + /// + /// Method similar to \#getCurrentToken() but that returns an + /// int instead of JsonToken (enum value). + /// + /// Use of int directly is typically more efficient on switch statements, + /// so this method may be useful when building low-overhead codecs. + /// Note, however, that effect may not be big enough to matter: make sure + /// to profile performance before deciding to use this method. + ///@since 2.8 + ///@return {@code int} matching one of constants from JsonTokenId. + int currentTokenId() { + return _currentTokenId(reference).integer; + } + + static final _getCurrentToken = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getCurrentToken") + .asFunction)>(); + + /// from: public abstract com.fasterxml.jackson.core.JsonToken getCurrentToken() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Alias for \#currentToken(), may be deprecated sometime after + /// Jackson 2.13 (will be removed from 3.0). + ///@return Type of the token this parser currently points to, + /// if any: null before any tokens have been read, and + jsontoken_.JsonToken getCurrentToken() { + return const jsontoken_.$JsonTokenType() + .fromRef(_getCurrentToken(reference).object); + } + + static final _getCurrentTokenId = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getCurrentTokenId") + .asFunction)>(); + + /// from: public abstract int getCurrentTokenId() + /// + /// Deprecated alias for \#currentTokenId(). + ///@return {@code int} matching one of constants from JsonTokenId. + ///@deprecated Since 2.12 use \#currentTokenId instead + int getCurrentTokenId() { + return _getCurrentTokenId(reference).integer; + } + + static final _hasCurrentToken = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__hasCurrentToken") + .asFunction)>(); + + /// from: public abstract boolean hasCurrentToken() + /// + /// Method for checking whether parser currently points to + /// a token (and data for that token is available). + /// Equivalent to check for parser.getCurrentToken() != null. + ///@return True if the parser just returned a valid + /// token via \#nextToken; false otherwise (parser + /// was just constructed, encountered end-of-input + /// and returned null from \#nextToken, or the token + /// has been consumed) + bool hasCurrentToken() { + return _hasCurrentToken(reference).boolean; + } + + static final _hasTokenId = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Int32)>>("JsonParser__hasTokenId") + .asFunction, int)>(); + + /// from: public abstract boolean hasTokenId(int id) + /// + /// Method that is functionally equivalent to: + /// + /// return currentTokenId() == id + /// + /// but may be more efficiently implemented. + /// + /// Note that no traversal or conversion is performed; so in some + /// cases calling method like \#isExpectedStartArrayToken() + /// is necessary instead. + ///@param id Token id to match (from (@link JsonTokenId}) + ///@return {@code True} if the parser current points to specified token + ///@since 2.5 + bool hasTokenId( + int id, + ) { + return _hasTokenId(reference, id).boolean; + } + + static final _hasToken = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonParser__hasToken") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public abstract boolean hasToken(com.fasterxml.jackson.core.JsonToken t) + /// + /// Method that is functionally equivalent to: + /// + /// return currentToken() == t + /// + /// but may be more efficiently implemented. + /// + /// Note that no traversal or conversion is performed; so in some + /// cases calling method like \#isExpectedStartArrayToken() + /// is necessary instead. + ///@param t Token to match + ///@return {@code True} if the parser current points to specified token + ///@since 2.6 + bool hasToken( + jsontoken_.JsonToken t, + ) { + return _hasToken(reference, t.reference).boolean; + } + + static final _isExpectedStartArrayToken = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__isExpectedStartArrayToken") + .asFunction)>(); + + /// from: public boolean isExpectedStartArrayToken() + /// + /// Specialized accessor that can be used to verify that the current + /// token indicates start array (usually meaning that current token + /// is JsonToken\#START_ARRAY) when start array is expected. + /// For some specialized parsers this can return true for other cases + /// as well; this is usually done to emulate arrays in cases underlying + /// format is ambiguous (XML, for example, has no format-level difference + /// between Objects and Arrays; it just has elements). + /// + /// Default implementation is equivalent to: + ///
+  ///   currentToken() == JsonToken.START_ARRAY
+  ///
+ /// but may be overridden by custom parser implementations. + ///@return True if the current token can be considered as a + /// start-array marker (such JsonToken\#START_ARRAY); + /// {@code false} if not + bool isExpectedStartArrayToken() { + return _isExpectedStartArrayToken(reference).boolean; + } + + static final _isExpectedStartObjectToken = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__isExpectedStartObjectToken") + .asFunction)>(); + + /// from: public boolean isExpectedStartObjectToken() + /// + /// Similar to \#isExpectedStartArrayToken(), but checks whether stream + /// currently points to JsonToken\#START_OBJECT. + ///@return True if the current token can be considered as a + /// start-array marker (such JsonToken\#START_OBJECT); + /// {@code false} if not + ///@since 2.5 + bool isExpectedStartObjectToken() { + return _isExpectedStartObjectToken(reference).boolean; + } + + static final _isExpectedNumberIntToken = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__isExpectedNumberIntToken") + .asFunction)>(); + + /// from: public boolean isExpectedNumberIntToken() + /// + /// Similar to \#isExpectedStartArrayToken(), but checks whether stream + /// currently points to JsonToken\#VALUE_NUMBER_INT. + /// + /// The initial use case is for XML backend to efficiently (attempt to) coerce + /// textual content into numbers. + ///@return True if the current token can be considered as a + /// start-array marker (such JsonToken\#VALUE_NUMBER_INT); + /// {@code false} if not + ///@since 2.12 + bool isExpectedNumberIntToken() { + return _isExpectedNumberIntToken(reference).boolean; + } + + static final _isNaN = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__isNaN") + .asFunction)>(); + + /// from: public boolean isNaN() + /// + /// Access for checking whether current token is a numeric value token, but + /// one that is of "not-a-number" (NaN) variety (including both "NaN" AND + /// positive/negative infinity!): not supported by all formats, + /// but often supported for JsonToken\#VALUE_NUMBER_FLOAT. + /// NOTE: roughly equivalent to calling !Double.isFinite() + /// on value you would get from calling \#getDoubleValue(). + ///@return {@code True} if the current token is of type JsonToken\#VALUE_NUMBER_FLOAT + /// but represents a "Not a Number"; {@code false} for other tokens and regular + /// floating-point numbers + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + ///@since 2.9 + bool isNaN() { + return _isNaN(reference).boolean; + } + + static final _clearCurrentToken = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__clearCurrentToken") + .asFunction)>(); + + /// from: public abstract void clearCurrentToken() + /// + /// Method called to "consume" the current token by effectively + /// removing it so that \#hasCurrentToken returns false, and + /// \#getCurrentToken null). + /// Cleared token value can still be accessed by calling + /// \#getLastClearedToken (if absolutely needed), but + /// usually isn't. + /// + /// Method was added to be used by the optional data binder, since + /// it has to be able to consume last token used for binding (so that + /// it will not be used again). + void clearCurrentToken() { + return _clearCurrentToken(reference).check(); + } + + static final _getLastClearedToken = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getLastClearedToken") + .asFunction)>(); + + /// from: public abstract com.fasterxml.jackson.core.JsonToken getLastClearedToken() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that can be called to get the last token that was + /// cleared using \#clearCurrentToken. This is not necessarily + /// the latest token read. + /// Will return null if no tokens have been cleared, + /// or if parser has been closed. + ///@return Last cleared token, if any; {@code null} otherwise + jsontoken_.JsonToken getLastClearedToken() { + return const jsontoken_.$JsonTokenType() + .fromRef(_getLastClearedToken(reference).object); + } + + static final _overrideCurrentName = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonParser__overrideCurrentName") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public abstract void overrideCurrentName(java.lang.String name) + /// + /// Method that can be used to change what is considered to be + /// the current (field) name. + /// May be needed to support non-JSON data formats or unusual binding + /// conventions; not needed for typical processing. + /// + /// Note that use of this method should only be done as sort of last + /// resort, as it is a work-around for regular operation. + ///@param name Name to use as the current name; may be null. + void overrideCurrentName( + jni.JString name, + ) { + return _overrideCurrentName(reference, name.reference).check(); + } + + static final _getCurrentName = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getCurrentName") + .asFunction)>(); + + /// from: public abstract java.lang.String getCurrentName() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Alias of \#currentName(). + ///@return Name of the current field in the parsing context + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + jni.JString getCurrentName() { + return const jni.JStringType().fromRef(_getCurrentName(reference).object); + } + + static final _currentName = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__currentName") + .asFunction)>(); + + /// from: public java.lang.String currentName() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that can be called to get the name associated with + /// the current token: for JsonToken\#FIELD_NAMEs it will + /// be the same as what \#getText returns; + /// for field values it will be preceding field name; + /// and for others (array values, root-level values) null. + ///@return Name of the current field in the parsing context + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + ///@since 2.10 + jni.JString currentName() { + return const jni.JStringType().fromRef(_currentName(reference).object); + } + + static final _getText = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getText") + .asFunction)>(); + + /// from: public abstract java.lang.String getText() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for accessing textual representation of the current token; + /// if no current token (before first call to \#nextToken, or + /// after encountering end-of-input), returns null. + /// Method can be called for any token type. + ///@return Textual value associated with the current token (one returned + /// by \#nextToken() or other iteration methods) + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + jni.JString getText() { + return const jni.JStringType().fromRef(_getText(reference).object); + } + + static final _getText1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonParser__getText1") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public int getText(java.io.Writer writer) + /// + /// Method to read the textual representation of the current token in chunks and + /// pass it to the given Writer. + /// Conceptually same as calling: + ///
+  ///  writer.write(parser.getText());
+  ///
+ /// but should typically be more efficient as longer content does need to + /// be combined into a single String to return, and write + /// can occur directly from intermediate buffers Jackson uses. + ///@param writer Writer to write textual content to + ///@return The number of characters written to the Writer + ///@throws IOException for low-level read issues or writes using passed + /// {@code writer}, or + /// JsonParseException for decoding problems + ///@since 2.8 + int getText1( + jni.JObject writer, + ) { + return _getText1(reference, writer.reference).integer; + } + + static final _getTextCharacters = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getTextCharacters") + .asFunction)>(); + + /// from: public abstract char[] getTextCharacters() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method similar to \#getText, but that will return + /// underlying (unmodifiable) character array that contains + /// textual value, instead of constructing a String object + /// to contain this information. + /// Note, however, that: + ///
    + ///
  • Textual contents are not guaranteed to start at + /// index 0 (rather, call \#getTextOffset) to + /// know the actual offset + ///
  • + ///
  • Length of textual contents may be less than the + /// length of returned buffer: call \#getTextLength + /// for actual length of returned content. + ///
  • + ///
+ /// + /// Note that caller __MUST NOT__ modify the returned + /// character array in any way -- doing so may corrupt + /// current parser state and render parser instance useless. + /// + /// The only reason to call this method (over \#getText) + /// is to avoid construction of a String object (which + /// will make a copy of contents). + ///@return Buffer that contains the current textual value (but not necessarily + /// at offset 0, and not necessarily until the end of buffer) + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + jni.JArray getTextCharacters() { + return const jni.JArrayType(jni.jcharType()) + .fromRef(_getTextCharacters(reference).object); + } + + static final _getTextLength = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getTextLength") + .asFunction)>(); + + /// from: public abstract int getTextLength() + /// + /// Accessor used with \#getTextCharacters, to know length + /// of String stored in returned buffer. + ///@return Number of characters within buffer returned + /// by \#getTextCharacters that are part of + /// textual content of the current token. + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + int getTextLength() { + return _getTextLength(reference).integer; + } + + static final _getTextOffset = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getTextOffset") + .asFunction)>(); + + /// from: public abstract int getTextOffset() + /// + /// Accessor used with \#getTextCharacters, to know offset + /// of the first text content character within buffer. + ///@return Offset of the first character within buffer returned + /// by \#getTextCharacters that is part of + /// textual content of the current token. + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + int getTextOffset() { + return _getTextOffset(reference).integer; + } + + static final _hasTextCharacters = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__hasTextCharacters") + .asFunction)>(); + + /// from: public abstract boolean hasTextCharacters() + /// + /// Method that can be used to determine whether calling of + /// \#getTextCharacters would be the most efficient + /// way to access textual content for the event parser currently + /// points to. + /// + /// Default implementation simply returns false since only actual + /// implementation class has knowledge of its internal buffering + /// state. + /// Implementations are strongly encouraged to properly override + /// this method, to allow efficient copying of content by other + /// code. + ///@return True if parser currently has character array that can + /// be efficiently returned via \#getTextCharacters; false + /// means that it may or may not exist + bool hasTextCharacters() { + return _hasTextCharacters(reference).boolean; + } + + static final _getNumberValue = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getNumberValue") + .asFunction)>(); + + /// from: public abstract java.lang.Number getNumberValue() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Generic number value accessor method that will work for + /// all kinds of numeric values. It will return the optimal + /// (simplest/smallest possible) wrapper object that can + /// express the numeric value just parsed. + ///@return Numeric value of the current token in its most optimal + /// representation + ///@throws IOException Problem with access: JsonParseException if + /// the current token is not numeric, or if decoding of the value fails + /// (invalid format for numbers); plain IOException if underlying + /// content read fails (possible if values are extracted lazily) + jni.JNumber getNumberValue() { + return const jni.JNumberType().fromRef(_getNumberValue(reference).object); + } + + static final _getNumberValueExact = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getNumberValueExact") + .asFunction)>(); + + /// from: public java.lang.Number getNumberValueExact() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method similar to \#getNumberValue with the difference that + /// for floating-point numbers value returned may be BigDecimal + /// if the underlying format does not store floating-point numbers using + /// native representation: for example, textual formats represent numbers + /// as Strings (which are 10-based), and conversion to java.lang.Double + /// is potentially lossy operation. + /// + /// Default implementation simply returns \#getNumberValue() + ///@return Numeric value of the current token using most accurate representation + ///@throws IOException Problem with access: JsonParseException if + /// the current token is not numeric, or if decoding of the value fails + /// (invalid format for numbers); plain IOException if underlying + /// content read fails (possible if values are extracted lazily) + ///@since 2.12 + jni.JNumber getNumberValueExact() { + return const jni.JNumberType() + .fromRef(_getNumberValueExact(reference).object); + } + + static final _getNumberType = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getNumberType") + .asFunction)>(); + + /// from: public abstract com.fasterxml.jackson.core.JsonParser.NumberType getNumberType() + /// The returned object must be released after use, by calling the [release] method. + /// + /// If current token is of type + /// JsonToken\#VALUE_NUMBER_INT or + /// JsonToken\#VALUE_NUMBER_FLOAT, returns + /// one of NumberType constants; otherwise returns null. + ///@return Type of current number, if parser points to numeric token; {@code null} otherwise + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + JsonParser_NumberType getNumberType() { + return const $JsonParser_NumberTypeType() + .fromRef(_getNumberType(reference).object); + } + + static final _getByteValue = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getByteValue") + .asFunction)>(); + + /// from: public byte getByteValue() + /// + /// Numeric accessor that can be called when the current + /// token is of type JsonToken\#VALUE_NUMBER_INT and + /// it can be expressed as a value of Java byte primitive type. + /// Note that in addition to "natural" input range of {@code [-128, 127]}, + /// this also allows "unsigned 8-bit byte" values {@code [128, 255]}: + /// but for this range value will be translated by truncation, leading + /// to sign change. + /// + /// It can also be called for JsonToken\#VALUE_NUMBER_FLOAT; + /// if so, it is equivalent to calling \#getDoubleValue + /// and then casting; except for possible overflow/underflow + /// exception. + /// + /// Note: if the resulting integer value falls outside range of + /// {@code [-128, 255]}, + /// a InputCoercionException + /// will be thrown to indicate numeric overflow/underflow. + ///@return Current number value as {@code byte} (if numeric token within + /// range of {@code [-128, 255]}); otherwise exception thrown + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + int getByteValue() { + return _getByteValue(reference).byte; + } + + static final _getShortValue = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getShortValue") + .asFunction)>(); + + /// from: public short getShortValue() + /// + /// Numeric accessor that can be called when the current + /// token is of type JsonToken\#VALUE_NUMBER_INT and + /// it can be expressed as a value of Java short primitive type. + /// It can also be called for JsonToken\#VALUE_NUMBER_FLOAT; + /// if so, it is equivalent to calling \#getDoubleValue + /// and then casting; except for possible overflow/underflow + /// exception. + /// + /// Note: if the resulting integer value falls outside range of + /// Java short, a InputCoercionException + /// will be thrown to indicate numeric overflow/underflow. + ///@return Current number value as {@code short} (if numeric token within + /// Java 16-bit signed {@code short} range); otherwise exception thrown + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + int getShortValue() { + return _getShortValue(reference).short; + } + + static final _getIntValue = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getIntValue") + .asFunction)>(); + + /// from: public abstract int getIntValue() + /// + /// Numeric accessor that can be called when the current + /// token is of type JsonToken\#VALUE_NUMBER_INT and + /// it can be expressed as a value of Java int primitive type. + /// It can also be called for JsonToken\#VALUE_NUMBER_FLOAT; + /// if so, it is equivalent to calling \#getDoubleValue + /// and then casting; except for possible overflow/underflow + /// exception. + /// + /// Note: if the resulting integer value falls outside range of + /// Java {@code int}, a InputCoercionException + /// may be thrown to indicate numeric overflow/underflow. + ///@return Current number value as {@code int} (if numeric token within + /// Java 32-bit signed {@code int} range); otherwise exception thrown + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + int getIntValue() { + return _getIntValue(reference).integer; + } + + static final _getLongValue = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getLongValue") + .asFunction)>(); + + /// from: public abstract long getLongValue() + /// + /// Numeric accessor that can be called when the current + /// token is of type JsonToken\#VALUE_NUMBER_INT and + /// it can be expressed as a Java long primitive type. + /// It can also be called for JsonToken\#VALUE_NUMBER_FLOAT; + /// if so, it is equivalent to calling \#getDoubleValue + /// and then casting to int; except for possible overflow/underflow + /// exception. + /// + /// Note: if the token is an integer, but its value falls + /// outside of range of Java long, a InputCoercionException + /// may be thrown to indicate numeric overflow/underflow. + ///@return Current number value as {@code long} (if numeric token within + /// Java 32-bit signed {@code long} range); otherwise exception thrown + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + int getLongValue() { + return _getLongValue(reference).long; + } + + static final _getBigIntegerValue = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getBigIntegerValue") + .asFunction)>(); + + /// from: public abstract java.math.BigInteger getBigIntegerValue() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Numeric accessor that can be called when the current + /// token is of type JsonToken\#VALUE_NUMBER_INT and + /// it can not be used as a Java long primitive type due to its + /// magnitude. + /// It can also be called for JsonToken\#VALUE_NUMBER_FLOAT; + /// if so, it is equivalent to calling \#getDecimalValue + /// and then constructing a BigInteger from that value. + ///@return Current number value as BigInteger (if numeric token); + /// otherwise exception thrown + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + jni.JObject getBigIntegerValue() { + return const jni.JObjectType() + .fromRef(_getBigIntegerValue(reference).object); + } + + static final _getFloatValue = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getFloatValue") + .asFunction)>(); + + /// from: public abstract float getFloatValue() + /// + /// Numeric accessor that can be called when the current + /// token is of type JsonToken\#VALUE_NUMBER_FLOAT and + /// it can be expressed as a Java float primitive type. + /// It can also be called for JsonToken\#VALUE_NUMBER_INT; + /// if so, it is equivalent to calling \#getLongValue + /// and then casting; except for possible overflow/underflow + /// exception. + /// + /// Note: if the value falls + /// outside of range of Java float, a InputCoercionException + /// will be thrown to indicate numeric overflow/underflow. + ///@return Current number value as {@code float} (if numeric token within + /// Java {@code float} range); otherwise exception thrown + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + double getFloatValue() { + return _getFloatValue(reference).float; + } + + static final _getDoubleValue = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getDoubleValue") + .asFunction)>(); + + /// from: public abstract double getDoubleValue() + /// + /// Numeric accessor that can be called when the current + /// token is of type JsonToken\#VALUE_NUMBER_FLOAT and + /// it can be expressed as a Java double primitive type. + /// It can also be called for JsonToken\#VALUE_NUMBER_INT; + /// if so, it is equivalent to calling \#getLongValue + /// and then casting; except for possible overflow/underflow + /// exception. + /// + /// Note: if the value falls + /// outside of range of Java double, a InputCoercionException + /// will be thrown to indicate numeric overflow/underflow. + ///@return Current number value as {@code double} (if numeric token within + /// Java {@code double} range); otherwise exception thrown + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + double getDoubleValue() { + return _getDoubleValue(reference).doubleFloat; + } + + static final _getDecimalValue = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getDecimalValue") + .asFunction)>(); + + /// from: public abstract java.math.BigDecimal getDecimalValue() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Numeric accessor that can be called when the current + /// token is of type JsonToken\#VALUE_NUMBER_FLOAT or + /// JsonToken\#VALUE_NUMBER_INT. No under/overflow exceptions + /// are ever thrown. + ///@return Current number value as BigDecimal (if numeric token); + /// otherwise exception thrown + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + jni.JObject getDecimalValue() { + return const jni.JObjectType().fromRef(_getDecimalValue(reference).object); + } + + static final _getBooleanValue = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getBooleanValue") + .asFunction)>(); + + /// from: public boolean getBooleanValue() + /// + /// Convenience accessor that can be called when the current + /// token is JsonToken\#VALUE_TRUE or + /// JsonToken\#VALUE_FALSE, to return matching {@code boolean} + /// value. + /// If the current token is of some other type, JsonParseException + /// will be thrown + ///@return {@code True} if current token is {@code JsonToken.VALUE_TRUE}, + /// {@code false} if current token is {@code JsonToken.VALUE_FALSE}; + /// otherwise throws JsonParseException + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + bool getBooleanValue() { + return _getBooleanValue(reference).boolean; + } + + static final _getEmbeddedObject = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getEmbeddedObject") + .asFunction)>(); + + /// from: public java.lang.Object getEmbeddedObject() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Accessor that can be called if (and only if) the current token + /// is JsonToken\#VALUE_EMBEDDED_OBJECT. For other token types, + /// null is returned. + /// + /// Note: only some specialized parser implementations support + /// embedding of objects (usually ones that are facades on top + /// of non-streaming sources, such as object trees). One exception + /// is access to binary content (whether via base64 encoding or not) + /// which typically is accessible using this method, as well as + /// \#getBinaryValue(). + ///@return Embedded value (usually of "native" type supported by format) + /// for the current token, if any; {@code null otherwise} + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + jni.JObject getEmbeddedObject() { + return const jni.JObjectType() + .fromRef(_getEmbeddedObject(reference).object); + } + + static final _getBinaryValue = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonParser__getBinaryValue") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public abstract byte[] getBinaryValue(com.fasterxml.jackson.core.Base64Variant bv) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that can be used to read (and consume -- results + /// may not be accessible using other methods after the call) + /// base64-encoded binary data + /// included in the current textual JSON value. + /// It works similar to getting String value via \#getText + /// and decoding result (except for decoding part), + /// but should be significantly more performant. + /// + /// Note that non-decoded textual contents of the current token + /// are not guaranteed to be accessible after this method + /// is called. Current implementation, for example, clears up + /// textual content during decoding. + /// Decoded binary content, however, will be retained until + /// parser is advanced to the next event. + ///@param bv Expected variant of base64 encoded + /// content (see Base64Variants for definitions + /// of "standard" variants). + ///@return Decoded binary data + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + jni.JArray getBinaryValue( + jni.JObject bv, + ) { + return const jni.JArrayType(jni.jbyteType()) + .fromRef(_getBinaryValue(reference, bv.reference).object); + } + + static final _getBinaryValue1 = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getBinaryValue1") + .asFunction)>(); + + /// from: public byte[] getBinaryValue() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Convenience alternative to \#getBinaryValue(Base64Variant) + /// that defaults to using + /// Base64Variants\#getDefaultVariant as the default encoding. + ///@return Decoded binary data + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + jni.JArray getBinaryValue1() { + return const jni.JArrayType(jni.jbyteType()) + .fromRef(_getBinaryValue1(reference).object); + } + + static final _readBinaryValue = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonParser__readBinaryValue") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public int readBinaryValue(java.io.OutputStream out) + /// + /// Method that can be used as an alternative to \#getBigIntegerValue(), + /// especially when value can be large. The main difference (beyond method + /// of returning content using OutputStream instead of as byte array) + /// is that content will NOT remain accessible after method returns: any content + /// processed will be consumed and is not buffered in any way. If caller needs + /// buffering, it has to implement it. + ///@param out Output stream to use for passing decoded binary data + ///@return Number of bytes that were decoded and written via OutputStream + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + ///@since 2.1 + int readBinaryValue( + jni.JObject out, + ) { + return _readBinaryValue(reference, out.reference).integer; + } + + static final _readBinaryValue1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>("JsonParser__readBinaryValue1") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); + + /// from: public int readBinaryValue(com.fasterxml.jackson.core.Base64Variant bv, java.io.OutputStream out) + /// + /// Similar to \#readBinaryValue(OutputStream) but allows explicitly + /// specifying base64 variant to use. + ///@param bv base64 variant to use + ///@param out Output stream to use for passing decoded binary data + ///@return Number of bytes that were decoded and written via OutputStream + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + ///@since 2.1 + int readBinaryValue1( + jni.JObject bv, + jni.JObject out, + ) { + return _readBinaryValue1(reference, bv.reference, out.reference).integer; + } + + static final _getValueAsInt = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getValueAsInt") + .asFunction)>(); + + /// from: public int getValueAsInt() + /// + /// Method that will try to convert value of current token to a + /// Java {@code int} value. + /// Numbers are coerced using default Java rules; booleans convert to 0 (false) + /// and 1 (true), and Strings are parsed using default Java language integer + /// parsing rules. + /// + /// If representation can not be converted to an int (including structured type + /// markers like start/end Object/Array) + /// default value of __0__ will be returned; no exceptions are thrown. + ///@return {@code int} value current token is converted to, if possible; exception thrown + /// otherwise + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + int getValueAsInt() { + return _getValueAsInt(reference).integer; + } + + static final _getValueAsInt1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Int32)>>("JsonParser__getValueAsInt1") + .asFunction, int)>(); + + /// from: public int getValueAsInt(int def) + /// + /// Method that will try to convert value of current token to a + /// __int__. + /// Numbers are coerced using default Java rules; booleans convert to 0 (false) + /// and 1 (true), and Strings are parsed using default Java language integer + /// parsing rules. + /// + /// If representation can not be converted to an int (including structured type + /// markers like start/end Object/Array) + /// specified __def__ will be returned; no exceptions are thrown. + ///@param def Default value to return if conversion to {@code int} is not possible + ///@return {@code int} value current token is converted to, if possible; {@code def} otherwise + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + int getValueAsInt1( + int def, + ) { + return _getValueAsInt1(reference, def).integer; + } + + static final _getValueAsLong = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getValueAsLong") + .asFunction)>(); + + /// from: public long getValueAsLong() + /// + /// Method that will try to convert value of current token to a + /// __long__. + /// Numbers are coerced using default Java rules; booleans convert to 0 (false) + /// and 1 (true), and Strings are parsed using default Java language integer + /// parsing rules. + /// + /// If representation can not be converted to a long (including structured type + /// markers like start/end Object/Array) + /// default value of __0L__ will be returned; no exceptions are thrown. + ///@return {@code long} value current token is converted to, if possible; exception thrown + /// otherwise + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + int getValueAsLong() { + return _getValueAsLong(reference).long; + } + + static final _getValueAsLong1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Int64)>>("JsonParser__getValueAsLong1") + .asFunction, int)>(); + + /// from: public long getValueAsLong(long def) + /// + /// Method that will try to convert value of current token to a + /// __long__. + /// Numbers are coerced using default Java rules; booleans convert to 0 (false) + /// and 1 (true), and Strings are parsed using default Java language integer + /// parsing rules. + /// + /// If representation can not be converted to a long (including structured type + /// markers like start/end Object/Array) + /// specified __def__ will be returned; no exceptions are thrown. + ///@param def Default value to return if conversion to {@code long} is not possible + ///@return {@code long} value current token is converted to, if possible; {@code def} otherwise + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + int getValueAsLong1( + int def, + ) { + return _getValueAsLong1(reference, def).long; + } + + static final _getValueAsDouble = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getValueAsDouble") + .asFunction)>(); + + /// from: public double getValueAsDouble() + /// + /// Method that will try to convert value of current token to a Java + /// __double__. + /// Numbers are coerced using default Java rules; booleans convert to 0.0 (false) + /// and 1.0 (true), and Strings are parsed using default Java language floating + /// point parsing rules. + /// + /// If representation can not be converted to a double (including structured types + /// like Objects and Arrays), + /// default value of __0.0__ will be returned; no exceptions are thrown. + ///@return {@code double} value current token is converted to, if possible; exception thrown + /// otherwise + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + double getValueAsDouble() { + return _getValueAsDouble(reference).doubleFloat; + } + + static final _getValueAsDouble1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Double)>>("JsonParser__getValueAsDouble1") + .asFunction, double)>(); + + /// from: public double getValueAsDouble(double def) + /// + /// Method that will try to convert value of current token to a + /// Java __double__. + /// Numbers are coerced using default Java rules; booleans convert to 0.0 (false) + /// and 1.0 (true), and Strings are parsed using default Java language floating + /// point parsing rules. + /// + /// If representation can not be converted to a double (including structured types + /// like Objects and Arrays), + /// specified __def__ will be returned; no exceptions are thrown. + ///@param def Default value to return if conversion to {@code double} is not possible + ///@return {@code double} value current token is converted to, if possible; {@code def} otherwise + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + double getValueAsDouble1( + double def, + ) { + return _getValueAsDouble1(reference, def).doubleFloat; + } + + static final _getValueAsBoolean = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getValueAsBoolean") + .asFunction)>(); + + /// from: public boolean getValueAsBoolean() + /// + /// Method that will try to convert value of current token to a + /// __boolean__. + /// JSON booleans map naturally; integer numbers other than 0 map to true, and + /// 0 maps to false + /// and Strings 'true' and 'false' map to corresponding values. + /// + /// If representation can not be converted to a boolean value (including structured types + /// like Objects and Arrays), + /// default value of __false__ will be returned; no exceptions are thrown. + ///@return {@code boolean} value current token is converted to, if possible; exception thrown + /// otherwise + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + bool getValueAsBoolean() { + return _getValueAsBoolean(reference).boolean; + } + + static final _getValueAsBoolean1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Uint8)>>("JsonParser__getValueAsBoolean1") + .asFunction, int)>(); + + /// from: public boolean getValueAsBoolean(boolean def) + /// + /// Method that will try to convert value of current token to a + /// __boolean__. + /// JSON booleans map naturally; integer numbers other than 0 map to true, and + /// 0 maps to false + /// and Strings 'true' and 'false' map to corresponding values. + /// + /// If representation can not be converted to a boolean value (including structured types + /// like Objects and Arrays), + /// specified __def__ will be returned; no exceptions are thrown. + ///@param def Default value to return if conversion to {@code boolean} is not possible + ///@return {@code boolean} value current token is converted to, if possible; {@code def} otherwise + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + bool getValueAsBoolean1( + bool def, + ) { + return _getValueAsBoolean1(reference, def ? 1 : 0).boolean; + } + + static final _getValueAsString = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getValueAsString") + .asFunction)>(); + + /// from: public java.lang.String getValueAsString() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that will try to convert value of current token to a + /// java.lang.String. + /// JSON Strings map naturally; scalar values get converted to + /// their textual representation. + /// If representation can not be converted to a String value (including structured types + /// like Objects and Arrays and {@code null} token), default value of + /// __null__ will be returned; no exceptions are thrown. + ///@return String value current token is converted to, if possible; {@code null} otherwise + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + ///@since 2.1 + jni.JString getValueAsString() { + return const jni.JStringType().fromRef(_getValueAsString(reference).object); + } + + static final _getValueAsString1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonParser__getValueAsString1") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public abstract java.lang.String getValueAsString(java.lang.String def) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that will try to convert value of current token to a + /// java.lang.String. + /// JSON Strings map naturally; scalar values get converted to + /// their textual representation. + /// If representation can not be converted to a String value (including structured types + /// like Objects and Arrays and {@code null} token), specified default value + /// will be returned; no exceptions are thrown. + ///@param def Default value to return if conversion to {@code String} is not possible + ///@return String value current token is converted to, if possible; {@code def} otherwise + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + ///@since 2.1 + jni.JString getValueAsString1( + jni.JString def, + ) { + return const jni.JStringType() + .fromRef(_getValueAsString1(reference, def.reference).object); + } + + static final _canReadObjectId = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__canReadObjectId") + .asFunction)>(); + + /// from: public boolean canReadObjectId() + /// + /// Introspection method that may be called to see if the underlying + /// data format supports some kind of Object Ids natively (many do not; + /// for example, JSON doesn't). + /// + /// Default implementation returns true; overridden by data formats + /// that do support native Object Ids. Caller is expected to either + /// use a non-native notation (explicit property or such), or fail, + /// in case it can not use native object ids. + ///@return {@code True} if the format being read supports native Object Ids; + /// {@code false} if not + ///@since 2.3 + bool canReadObjectId() { + return _canReadObjectId(reference).boolean; + } + + static final _canReadTypeId = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__canReadTypeId") + .asFunction)>(); + + /// from: public boolean canReadTypeId() + /// + /// Introspection method that may be called to see if the underlying + /// data format supports some kind of Type Ids natively (many do not; + /// for example, JSON doesn't). + /// + /// Default implementation returns true; overridden by data formats + /// that do support native Type Ids. Caller is expected to either + /// use a non-native notation (explicit property or such), or fail, + /// in case it can not use native type ids. + ///@return {@code True} if the format being read supports native Type Ids; + /// {@code false} if not + ///@since 2.3 + bool canReadTypeId() { + return _canReadTypeId(reference).boolean; + } + + static final _getObjectId = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getObjectId") + .asFunction)>(); + + /// from: public java.lang.Object getObjectId() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that can be called to check whether current token + /// (one that was just read) has an associated Object id, and if + /// so, return it. + /// Note that while typically caller should check with \#canReadObjectId + /// first, it is not illegal to call this method even if that method returns + /// true; but if so, it will return null. This may be used to simplify calling + /// code. + /// + /// Default implementation will simply return null. + ///@return Native Object id associated with the current token, if any; {@code null} if none + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + ///@since 2.3 + jni.JObject getObjectId() { + return const jni.JObjectType().fromRef(_getObjectId(reference).object); + } + + static final _getTypeId = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__getTypeId") + .asFunction)>(); + + /// from: public java.lang.Object getTypeId() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that can be called to check whether current token + /// (one that was just read) has an associated type id, and if + /// so, return it. + /// Note that while typically caller should check with \#canReadTypeId + /// first, it is not illegal to call this method even if that method returns + /// true; but if so, it will return null. This may be used to simplify calling + /// code. + /// + /// Default implementation will simply return null. + ///@return Native Type Id associated with the current token, if any; {@code null} if none + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + ///@since 2.3 + jni.JObject getTypeId() { + return const jni.JObjectType().fromRef(_getTypeId(reference).object); + } + + static final _readValueAs = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonParser__readValueAs") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public T readValueAs(java.lang.Class valueType) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method to deserialize JSON content into a non-container + /// type (it can be an array type, however): typically a bean, array + /// or a wrapper type (like java.lang.Boolean). + /// __Note__: method can only be called if the parser has + /// an object codec assigned; this is true for parsers constructed + /// by MappingJsonFactory (from "jackson-databind" jar) + /// but not for JsonFactory (unless its setCodec + /// method has been explicitly called). + /// + /// This method may advance the event stream, for structured types + /// the current token will be the closing end marker (END_ARRAY, + /// END_OBJECT) of the bound structure. For non-structured Json types + /// (and for JsonToken\#VALUE_EMBEDDED_OBJECT) + /// stream is not advanced. + /// + /// Note: this method should NOT be used if the result type is a + /// container (java.util.Collection or java.util.Map. + /// The reason is that due to type erasure, key and value types + /// can not be introspected when using this method. + ///@param Nominal type parameter for value type + ///@param valueType Java type to read content as (passed to ObjectCodec that + /// deserializes content) + ///@return Java value read from content + ///@throws IOException if there is either an underlying I/O problem or decoding + /// issue at format layer + $T readValueAs<$T extends jni.JObject>( + jni.JObject valueType, { + required jni.JObjType<$T> T, + }) { + return T.fromRef(_readValueAs(reference, valueType.reference).object); + } + + static final _readValueAs1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonParser__readValueAs1") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public T readValueAs(com.fasterxml.jackson.core.type.TypeReference valueTypeRef) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method to deserialize JSON content into a Java type, reference + /// to which is passed as argument. Type is passed using so-called + /// "super type token" + /// and specifically needs to be used if the root type is a + /// parameterized (generic) container type. + /// __Note__: method can only be called if the parser has + /// an object codec assigned; this is true for parsers constructed + /// by MappingJsonFactory (defined in 'jackson-databind' bundle) + /// but not for JsonFactory (unless its setCodec + /// method has been explicitly called). + /// + /// This method may advance the event stream, for structured types + /// the current token will be the closing end marker (END_ARRAY, + /// END_OBJECT) of the bound structure. For non-structured Json types + /// (and for JsonToken\#VALUE_EMBEDDED_OBJECT) + /// stream is not advanced. + ///@param Nominal type parameter for value type + ///@param valueTypeRef Java type to read content as (passed to ObjectCodec that + /// deserializes content) + ///@return Java value read from content + ///@throws IOException if there is either an underlying I/O problem or decoding + /// issue at format layer + $T readValueAs1<$T extends jni.JObject>( + jni.JObject valueTypeRef, { + required jni.JObjType<$T> T, + }) { + return T.fromRef(_readValueAs1(reference, valueTypeRef.reference).object); + } + + static final _readValuesAs = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonParser__readValuesAs") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public java.util.Iterator readValuesAs(java.lang.Class valueType) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for reading sequence of Objects from parser stream, + /// all with same specified value type. + ///@param Nominal type parameter for value type + ///@param valueType Java type to read content as (passed to ObjectCodec that + /// deserializes content) + ///@return Iterator for reading multiple Java values from content + ///@throws IOException if there is either an underlying I/O problem or decoding + /// issue at format layer + jni.JIterator<$T> readValuesAs<$T extends jni.JObject>( + jni.JObject valueType, { + required jni.JObjType<$T> T, + }) { + return jni.JIteratorType(T) + .fromRef(_readValuesAs(reference, valueType.reference).object); + } + + static final _readValuesAs1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("JsonParser__readValuesAs1") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public java.util.Iterator readValuesAs(com.fasterxml.jackson.core.type.TypeReference valueTypeRef) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for reading sequence of Objects from parser stream, + /// all with same specified value type. + ///@param Nominal type parameter for value type + ///@param valueTypeRef Java type to read content as (passed to ObjectCodec that + /// deserializes content) + ///@return Iterator for reading multiple Java values from content + ///@throws IOException if there is either an underlying I/O problem or decoding + /// issue at format layer + jni.JIterator<$T> readValuesAs1<$T extends jni.JObject>( + jni.JObject valueTypeRef, { + required jni.JObjType<$T> T, + }) { + return jni.JIteratorType(T) + .fromRef(_readValuesAs1(reference, valueTypeRef.reference).object); + } + + static final _readValueAsTree = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser__readValueAsTree") + .asFunction)>(); + + /// from: public T readValueAsTree() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method to deserialize JSON content into equivalent "tree model", + /// represented by root TreeNode of resulting model. + /// For JSON Arrays it will an array node (with child nodes), + /// for objects object node (with child nodes), and for other types + /// matching leaf node type. Empty or whitespace documents are null. + ///@param Nominal type parameter for result node type (to reduce need for casting) + ///@return root of the document, or null if empty or whitespace. + ///@throws IOException if there is either an underlying I/O problem or decoding + /// issue at format layer + $T readValueAsTree<$T extends jni.JObject>({ + required jni.JObjType<$T> T, + }) { + return T.fromRef(_readValueAsTree(reference).object); + } +} + +final class $JsonParserType extends jni.JObjType { + const $JsonParserType(); + + @override + String get signature => r"Lcom/fasterxml/jackson/core/JsonParser;"; + + @override + JsonParser fromRef(jni.JObjectPtr ref) => JsonParser.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($JsonParserType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($JsonParserType) && other is $JsonParserType; + } +} + +/// from: com.fasterxml.jackson.core.JsonParser$Feature +/// +/// Enumeration that defines all on/off features for parsers. +class JsonParser_Feature extends jni.JObject { + @override + late final jni.JObjType $type = type; + + JsonParser_Feature.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $JsonParser_FeatureType(); + static final _values = + jniLookup>( + "JsonParser_Feature__values") + .asFunction(); + + /// from: static public com.fasterxml.jackson.core.JsonParser.Feature[] values() + /// The returned object must be released after use, by calling the [release] method. + static jni.JArray values() { + return const jni.JArrayType($JsonParser_FeatureType()) + .fromRef(_values().object); + } + + static final _valueOf = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser_Feature__valueOf") + .asFunction)>(); + + /// from: static public com.fasterxml.jackson.core.JsonParser.Feature valueOf(java.lang.String name) + /// The returned object must be released after use, by calling the [release] method. + static JsonParser_Feature valueOf( + jni.JString name, + ) { + return const $JsonParser_FeatureType() + .fromRef(_valueOf(name.reference).object); + } + + static final _collectDefaults = + jniLookup>( + "JsonParser_Feature__collectDefaults") + .asFunction(); + + /// from: static public int collectDefaults() + /// + /// Method that calculates bit set (flags) of all features that + /// are enabled by default. + ///@return Bit mask of all features that are enabled by default + static int collectDefaults() { + return _collectDefaults().integer; + } + + static final _enabledByDefault = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser_Feature__enabledByDefault") + .asFunction)>(); + + /// from: public boolean enabledByDefault() + bool enabledByDefault() { + return _enabledByDefault(reference).boolean; + } + + static final _enabledIn = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Int32)>>("JsonParser_Feature__enabledIn") + .asFunction, int)>(); + + /// from: public boolean enabledIn(int flags) + bool enabledIn( + int flags, + ) { + return _enabledIn(reference, flags).boolean; + } + + static final _getMask = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser_Feature__getMask") + .asFunction)>(); + + /// from: public int getMask() + int getMask() { + return _getMask(reference).integer; + } +} + +final class $JsonParser_FeatureType extends jni.JObjType { + const $JsonParser_FeatureType(); + + @override + String get signature => r"Lcom/fasterxml/jackson/core/JsonParser$Feature;"; + + @override + JsonParser_Feature fromRef(jni.JObjectPtr ref) => + JsonParser_Feature.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($JsonParser_FeatureType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($JsonParser_FeatureType) && + other is $JsonParser_FeatureType; + } +} + +/// from: com.fasterxml.jackson.core.JsonParser$NumberType +/// +/// Enumeration of possible "native" (optimal) types that can be +/// used for numbers. +class JsonParser_NumberType extends jni.JObject { + @override + late final jni.JObjType $type = type; + + JsonParser_NumberType.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $JsonParser_NumberTypeType(); + static final _values = + jniLookup>( + "JsonParser_NumberType__values") + .asFunction(); + + /// from: static public com.fasterxml.jackson.core.JsonParser.NumberType[] values() + /// The returned object must be released after use, by calling the [release] method. + static jni.JArray values() { + return const jni.JArrayType($JsonParser_NumberTypeType()) + .fromRef(_values().object); + } + + static final _valueOf = jniLookup< + ffi + .NativeFunction)>>( + "JsonParser_NumberType__valueOf") + .asFunction)>(); + + /// from: static public com.fasterxml.jackson.core.JsonParser.NumberType valueOf(java.lang.String name) + /// The returned object must be released after use, by calling the [release] method. + static JsonParser_NumberType valueOf( + jni.JString name, + ) { + return const $JsonParser_NumberTypeType() + .fromRef(_valueOf(name.reference).object); + } +} + +final class $JsonParser_NumberTypeType + extends jni.JObjType { + const $JsonParser_NumberTypeType(); + + @override + String get signature => r"Lcom/fasterxml/jackson/core/JsonParser$NumberType;"; + + @override + JsonParser_NumberType fromRef(jni.JObjectPtr ref) => + JsonParser_NumberType.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($JsonParser_NumberTypeType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($JsonParser_NumberTypeType) && + other is $JsonParser_NumberTypeType; + } +} diff --git a/pkgs/jnigen/test/jackson_core_test/third_party/c_based/dart_bindings/com/fasterxml/jackson/core/JsonToken.dart b/pkgs/jnigen/test/jackson_core_test/third_party/c_based/dart_bindings/com/fasterxml/jackson/core/JsonToken.dart new file mode 100644 index 000000000..4d80a8f75 --- /dev/null +++ b/pkgs/jnigen/test/jackson_core_test/third_party/c_based/dart_bindings/com/fasterxml/jackson/core/JsonToken.dart @@ -0,0 +1,237 @@ +// Generated from jackson-core which is licensed under the Apache License 2.0. +// The following copyright from the original authors applies. +// See https://github.com/FasterXML/jackson-core/blob/2.14/LICENSE +// +// Copyright (c) 2007 - The Jackson Project Authors +// Licensed under the Apache License, Version 2.0 (the "License") +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Autogenerated by jnigen. DO NOT EDIT! + +// ignore_for_file: annotate_overrides +// ignore_for_file: camel_case_extensions +// ignore_for_file: camel_case_types +// ignore_for_file: constant_identifier_names +// ignore_for_file: file_names +// ignore_for_file: lines_longer_than_80_chars +// ignore_for_file: no_leading_underscores_for_local_identifiers +// ignore_for_file: non_constant_identifier_names +// ignore_for_file: overridden_fields +// ignore_for_file: unnecessary_cast +// ignore_for_file: unused_element +// ignore_for_file: unused_field +// ignore_for_file: unused_import +// ignore_for_file: unused_local_variable +// ignore_for_file: unused_shown_name + +import "dart:isolate" show ReceivePort; +import "dart:ffi" as ffi; +import "package:jni/internal_helpers_for_jnigen.dart"; +import "package:jni/jni.dart" as jni; + +import "../../../../_init.dart"; + +/// from: com.fasterxml.jackson.core.JsonToken +/// +/// Enumeration for basic token types used for returning results +/// of parsing JSON content. +class JsonToken extends jni.JObject { + @override + late final jni.JObjType $type = type; + + JsonToken.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $JsonTokenType(); + static final _values = + jniLookup>( + "JsonToken__values") + .asFunction(); + + /// from: static public com.fasterxml.jackson.core.JsonToken[] values() + /// The returned object must be released after use, by calling the [release] method. + static jni.JArray values() { + return const jni.JArrayType($JsonTokenType()).fromRef(_values().object); + } + + static final _valueOf = jniLookup< + ffi + .NativeFunction)>>( + "JsonToken__valueOf") + .asFunction)>(); + + /// from: static public com.fasterxml.jackson.core.JsonToken valueOf(java.lang.String name) + /// The returned object must be released after use, by calling the [release] method. + static JsonToken valueOf( + jni.JString name, + ) { + return const $JsonTokenType().fromRef(_valueOf(name.reference).object); + } + + static final _id = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer)>>("JsonToken__id") + .asFunction)>(); + + /// from: public final int id() + int id() { + return _id(reference).integer; + } + + static final _asString = jniLookup< + ffi + .NativeFunction)>>( + "JsonToken__asString") + .asFunction)>(); + + /// from: public final java.lang.String asString() + /// The returned object must be released after use, by calling the [release] method. + jni.JString asString() { + return const jni.JStringType().fromRef(_asString(reference).object); + } + + static final _asCharArray = jniLookup< + ffi + .NativeFunction)>>( + "JsonToken__asCharArray") + .asFunction)>(); + + /// from: public final char[] asCharArray() + /// The returned object must be released after use, by calling the [release] method. + jni.JArray asCharArray() { + return const jni.JArrayType(jni.jcharType()) + .fromRef(_asCharArray(reference).object); + } + + static final _asByteArray = jniLookup< + ffi + .NativeFunction)>>( + "JsonToken__asByteArray") + .asFunction)>(); + + /// from: public final byte[] asByteArray() + /// The returned object must be released after use, by calling the [release] method. + jni.JArray asByteArray() { + return const jni.JArrayType(jni.jbyteType()) + .fromRef(_asByteArray(reference).object); + } + + static final _isNumeric = jniLookup< + ffi + .NativeFunction)>>( + "JsonToken__isNumeric") + .asFunction)>(); + + /// from: public final boolean isNumeric() + /// + /// @return {@code True} if this token is {@code VALUE_NUMBER_INT} or {@code VALUE_NUMBER_FLOAT}, + /// {@code false} otherwise + bool isNumeric() { + return _isNumeric(reference).boolean; + } + + static final _isStructStart = jniLookup< + ffi + .NativeFunction)>>( + "JsonToken__isStructStart") + .asFunction)>(); + + /// from: public final boolean isStructStart() + /// + /// Accessor that is functionally equivalent to: + /// + /// this == JsonToken.START_OBJECT || this == JsonToken.START_ARRAY + /// + ///@return {@code True} if this token is {@code START_OBJECT} or {@code START_ARRAY}, + /// {@code false} otherwise + ///@since 2.3 + bool isStructStart() { + return _isStructStart(reference).boolean; + } + + static final _isStructEnd = jniLookup< + ffi + .NativeFunction)>>( + "JsonToken__isStructEnd") + .asFunction)>(); + + /// from: public final boolean isStructEnd() + /// + /// Accessor that is functionally equivalent to: + /// + /// this == JsonToken.END_OBJECT || this == JsonToken.END_ARRAY + /// + ///@return {@code True} if this token is {@code END_OBJECT} or {@code END_ARRAY}, + /// {@code false} otherwise + ///@since 2.3 + bool isStructEnd() { + return _isStructEnd(reference).boolean; + } + + static final _isScalarValue = jniLookup< + ffi + .NativeFunction)>>( + "JsonToken__isScalarValue") + .asFunction)>(); + + /// from: public final boolean isScalarValue() + /// + /// Method that can be used to check whether this token represents + /// a valid non-structured value. This means all {@code VALUE_xxx} tokens; + /// excluding {@code START_xxx} and {@code END_xxx} tokens as well + /// {@code FIELD_NAME}. + ///@return {@code True} if this token is a scalar value token (one of + /// {@code VALUE_xxx} tokens), {@code false} otherwise + bool isScalarValue() { + return _isScalarValue(reference).boolean; + } + + static final _isBoolean = jniLookup< + ffi + .NativeFunction)>>( + "JsonToken__isBoolean") + .asFunction)>(); + + /// from: public final boolean isBoolean() + /// + /// @return {@code True} if this token is {@code VALUE_TRUE} or {@code VALUE_FALSE}, + /// {@code false} otherwise + bool isBoolean() { + return _isBoolean(reference).boolean; + } +} + +final class $JsonTokenType extends jni.JObjType { + const $JsonTokenType(); + + @override + String get signature => r"Lcom/fasterxml/jackson/core/JsonToken;"; + + @override + JsonToken fromRef(jni.JObjectPtr ref) => JsonToken.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($JsonTokenType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($JsonTokenType) && other is $JsonTokenType; + } +} diff --git a/pkgs/jnigen/test/jackson_core_test/third_party/c_based/dart_bindings/com/fasterxml/jackson/core/_package.dart b/pkgs/jnigen/test/jackson_core_test/third_party/c_based/dart_bindings/com/fasterxml/jackson/core/_package.dart new file mode 100644 index 000000000..cae2a52e6 --- /dev/null +++ b/pkgs/jnigen/test/jackson_core_test/third_party/c_based/dart_bindings/com/fasterxml/jackson/core/_package.dart @@ -0,0 +1,3 @@ +export "JsonFactory.dart"; +export "JsonParser.dart"; +export "JsonToken.dart"; diff --git a/pkgs/jnigen/test/jackson_core_test/third_party/dart_only/dart_bindings/com/fasterxml/jackson/core/JsonFactory.dart b/pkgs/jnigen/test/jackson_core_test/third_party/dart_only/dart_bindings/com/fasterxml/jackson/core/JsonFactory.dart new file mode 100644 index 000000000..3cdf2ff86 --- /dev/null +++ b/pkgs/jnigen/test/jackson_core_test/third_party/dart_only/dart_bindings/com/fasterxml/jackson/core/JsonFactory.dart @@ -0,0 +1,1895 @@ +// Generated from jackson-core which is licensed under the Apache License 2.0. +// The following copyright from the original authors applies. +// See https://github.com/FasterXML/jackson-core/blob/2.14/LICENSE +// +// Copyright (c) 2007 - The Jackson Project Authors +// Licensed under the Apache License, Version 2.0 (the "License") +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Autogenerated by jnigen. DO NOT EDIT! + +// ignore_for_file: annotate_overrides +// ignore_for_file: camel_case_extensions +// ignore_for_file: camel_case_types +// ignore_for_file: constant_identifier_names +// ignore_for_file: file_names +// ignore_for_file: lines_longer_than_80_chars +// ignore_for_file: no_leading_underscores_for_local_identifiers +// ignore_for_file: non_constant_identifier_names +// ignore_for_file: overridden_fields +// ignore_for_file: unnecessary_cast +// ignore_for_file: unused_element +// ignore_for_file: unused_field +// ignore_for_file: unused_import +// ignore_for_file: unused_local_variable +// ignore_for_file: unused_shown_name + +import "dart:isolate" show ReceivePort; +import "dart:ffi" as ffi; +import "package:jni/internal_helpers_for_jnigen.dart"; +import "package:jni/jni.dart" as jni; + +import "JsonParser.dart" as jsonparser_; + +/// from: com.fasterxml.jackson.core.JsonFactory +/// +/// The main factory class of Jackson package, used to configure and +/// construct reader (aka parser, JsonParser) +/// and writer (aka generator, JsonGenerator) +/// instances. +/// +/// Factory instances are thread-safe and reusable after configuration +/// (if any). Typically applications and services use only a single +/// globally shared factory instance, unless they need differently +/// configured factories. Factory reuse is important if efficiency matters; +/// most recycling of expensive construct is done on per-factory basis. +/// +/// Creation of a factory instance is a light-weight operation, +/// and since there is no need for pluggable alternative implementations +/// (as there is no "standard" JSON processor API to implement), +/// the default constructor is used for constructing factory +/// instances. +///@author Tatu Saloranta +class JsonFactory extends jni.JObject { + @override + late final jni.JObjType $type = type; + + JsonFactory.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = + jni.Jni.findJClass(r"com/fasterxml/jackson/core/JsonFactory"); + + /// The type which includes information such as the signature of this class. + static const type = $JsonFactoryType(); + + /// from: static public final java.lang.String FORMAT_NAME_JSON + /// + /// Name used to identify JSON format + /// (and returned by \#getFormatName() + static const FORMAT_NAME_JSON = r"""JSON"""; + + static final _id_DEFAULT_FACTORY_FEATURE_FLAGS = + jni.Jni.accessors.getStaticFieldIDOf( + _class.reference, + r"DEFAULT_FACTORY_FEATURE_FLAGS", + r"I", + ); + + /// from: static protected final int DEFAULT_FACTORY_FEATURE_FLAGS + /// + /// Bitfield (set of flags) of all factory features that are enabled by default. + static int get DEFAULT_FACTORY_FEATURE_FLAGS => jni.Jni.accessors + .getStaticField(_class.reference, _id_DEFAULT_FACTORY_FEATURE_FLAGS, + jni.JniCallType.intType) + .integer; + + static final _id_DEFAULT_PARSER_FEATURE_FLAGS = + jni.Jni.accessors.getStaticFieldIDOf( + _class.reference, + r"DEFAULT_PARSER_FEATURE_FLAGS", + r"I", + ); + + /// from: static protected final int DEFAULT_PARSER_FEATURE_FLAGS + /// + /// Bitfield (set of flags) of all parser features that are enabled + /// by default. + static int get DEFAULT_PARSER_FEATURE_FLAGS => jni.Jni.accessors + .getStaticField(_class.reference, _id_DEFAULT_PARSER_FEATURE_FLAGS, + jni.JniCallType.intType) + .integer; + + static final _id_DEFAULT_GENERATOR_FEATURE_FLAGS = + jni.Jni.accessors.getStaticFieldIDOf( + _class.reference, + r"DEFAULT_GENERATOR_FEATURE_FLAGS", + r"I", + ); + + /// from: static protected final int DEFAULT_GENERATOR_FEATURE_FLAGS + /// + /// Bitfield (set of flags) of all generator features that are enabled + /// by default. + static int get DEFAULT_GENERATOR_FEATURE_FLAGS => jni.Jni.accessors + .getStaticField(_class.reference, _id_DEFAULT_GENERATOR_FEATURE_FLAGS, + jni.JniCallType.intType) + .integer; + + static final _id_DEFAULT_ROOT_VALUE_SEPARATOR = + jni.Jni.accessors.getStaticFieldIDOf( + _class.reference, + r"DEFAULT_ROOT_VALUE_SEPARATOR", + r"Lcom/fasterxml/jackson/core/SerializableString;", + ); + + /// from: static public final com.fasterxml.jackson.core.SerializableString DEFAULT_ROOT_VALUE_SEPARATOR + /// The returned object must be released after use, by calling the [release] method. + static jni.JObject get DEFAULT_ROOT_VALUE_SEPARATOR => + const jni.JObjectType().fromRef(jni.Jni.accessors + .getStaticField(_class.reference, _id_DEFAULT_ROOT_VALUE_SEPARATOR, + jni.JniCallType.objectType) + .object); + + static final _id_new0 = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"", r"()V"); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + /// + /// Default constructor used to create factory instances. + /// Creation of a factory instance is a light-weight operation, + /// but it is still a good idea to reuse limited number of + /// factory instances (and quite often just a single instance): + /// factories are used as context for storing some reused + /// processing objects (such as symbol tables parsers use) + /// and this reuse only works within context of a single + /// factory instance. + factory JsonFactory() { + return JsonFactory.fromRef(jni.Jni.accessors + .newObjectWithArgs(_class.reference, _id_new0, []).object); + } + + static final _id_new1 = jni.Jni.accessors.getMethodIDOf(_class.reference, + r"", r"(Lcom/fasterxml/jackson/core/ObjectCodec;)V"); + + /// from: public void (com.fasterxml.jackson.core.ObjectCodec oc) + /// The returned object must be released after use, by calling the [release] method. + factory JsonFactory.new1( + jni.JObject oc, + ) { + return JsonFactory.fromRef(jni.Jni.accessors + .newObjectWithArgs(_class.reference, _id_new1, [oc.reference]).object); + } + + static final _id_new2 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"", + r"(Lcom/fasterxml/jackson/core/JsonFactory;Lcom/fasterxml/jackson/core/ObjectCodec;)V"); + + /// from: protected void (com.fasterxml.jackson.core.JsonFactory src, com.fasterxml.jackson.core.ObjectCodec codec) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Constructor used when copy()ing a factory instance. + ///@param src Original factory to copy settings from + ///@param codec Databinding-level codec to use, if any + ///@since 2.2.1 + factory JsonFactory.new2( + JsonFactory src, + jni.JObject codec, + ) { + return JsonFactory.fromRef(jni.Jni.accessors.newObjectWithArgs( + _class.reference, _id_new2, [src.reference, codec.reference]).object); + } + + static final _id_new3 = jni.Jni.accessors.getMethodIDOf(_class.reference, + r"", r"(Lcom/fasterxml/jackson/core/JsonFactoryBuilder;)V"); + + /// from: public void (com.fasterxml.jackson.core.JsonFactoryBuilder b) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Constructor used by JsonFactoryBuilder for instantiation. + ///@param b Builder that contains settings to use + ///@since 2.10 + factory JsonFactory.new3( + jni.JObject b, + ) { + return JsonFactory.fromRef(jni.Jni.accessors + .newObjectWithArgs(_class.reference, _id_new3, [b.reference]).object); + } + + static final _id_new4 = jni.Jni.accessors.getMethodIDOf(_class.reference, + r"", r"(Lcom/fasterxml/jackson/core/TSFBuilder;Z)V"); + + /// from: protected void (com.fasterxml.jackson.core.TSFBuilder b, boolean bogus) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Constructor for subtypes; needed to work around the fact that before 3.0, + /// this factory has cumbersome dual role as generic type as well as actual + /// implementation for json. + ///@param b Builder that contains settings to use + ///@param bogus Argument only needed to separate constructor signature; ignored + factory JsonFactory.new4( + jni.JObject b, + bool bogus, + ) { + return JsonFactory.fromRef(jni.Jni.accessors.newObjectWithArgs( + _class.reference, _id_new4, [b.reference, bogus ? 1 : 0]).object); + } + + static final _id_rebuild = jni.Jni.accessors.getMethodIDOf(_class.reference, + r"rebuild", r"()Lcom/fasterxml/jackson/core/TSFBuilder;"); + + /// from: public com.fasterxml.jackson.core.TSFBuilder rebuild() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that allows construction of differently configured factory, starting + /// with settings of this factory. + ///@return Builder instance to use + ///@since 2.10 + jni.JObject rebuild() { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, _id_rebuild, jni.JniCallType.objectType, []).object); + } + + static final _id_builder = jni.Jni.accessors.getStaticMethodIDOf( + _class.reference, + r"builder", + r"()Lcom/fasterxml/jackson/core/TSFBuilder;"); + + /// from: static public com.fasterxml.jackson.core.TSFBuilder builder() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Main factory method to use for constructing JsonFactory instances with + /// different configuration: creates and returns a builder for collecting configuration + /// settings; instance created by calling {@code build()} after all configuration + /// set. + /// + /// NOTE: signature unfortunately does not expose true implementation type; this + /// will be fixed in 3.0. + ///@return Builder instance to use + static jni.JObject builder() { + return const jni.JObjectType().fromRef(jni.Jni.accessors + .callStaticMethodWithArgs(_class.reference, _id_builder, + jni.JniCallType.objectType, []).object); + } + + static final _id_copy = jni.Jni.accessors.getMethodIDOf( + _class.reference, r"copy", r"()Lcom/fasterxml/jackson/core/JsonFactory;"); + + /// from: public com.fasterxml.jackson.core.JsonFactory copy() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing a new JsonFactory that has + /// the same settings as this instance, but is otherwise + /// independent (i.e. nothing is actually shared, symbol tables + /// are separate). + /// Note that ObjectCodec reference is not copied but is + /// set to null; caller typically needs to set it after calling + /// this method. Reason for this is that the codec is used for + /// callbacks, and assumption is that there is strict 1-to-1 + /// mapping between codec, factory. Caller has to, then, explicitly + /// set codec after making the copy. + ///@return Copy of this factory instance + ///@since 2.1 + JsonFactory copy() { + return const $JsonFactoryType().fromRef(jni.Jni.accessors + .callMethodWithArgs( + reference, _id_copy, jni.JniCallType.objectType, []).object); + } + + static final _id_readResolve = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"readResolve", r"()Ljava/lang/Object;"); + + /// from: protected java.lang.Object readResolve() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that we need to override to actually make restoration go + /// through constructors etc: needed to allow JDK serializability of + /// factory instances. + /// + /// Note: must be overridden by sub-classes as well. + ///@return Newly constructed instance + jni.JObject readResolve() { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, _id_readResolve, jni.JniCallType.objectType, []).object); + } + + static final _id_requiresPropertyOrdering = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"requiresPropertyOrdering", r"()Z"); + + /// from: public boolean requiresPropertyOrdering() + /// + /// Introspection method that higher-level functionality may call + /// to see whether underlying data format requires a stable ordering + /// of object properties or not. + /// This is usually used for determining + /// whether to force a stable ordering (like alphabetic ordering by name) + /// if no ordering if explicitly specified. + /// + /// Default implementation returns false as JSON does NOT + /// require stable ordering. Formats that require ordering include positional + /// textual formats like CSV, and schema-based binary formats + /// like Avro. + ///@return Whether format supported by this factory + /// requires Object properties to be ordered. + ///@since 2.3 + bool requiresPropertyOrdering() { + return jni.Jni.accessors.callMethodWithArgs(reference, + _id_requiresPropertyOrdering, jni.JniCallType.booleanType, []).boolean; + } + + static final _id_canHandleBinaryNatively = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"canHandleBinaryNatively", r"()Z"); + + /// from: public boolean canHandleBinaryNatively() + /// + /// Introspection method that higher-level functionality may call + /// to see whether underlying data format can read and write binary + /// data natively; that is, embeded it as-is without using encodings + /// such as Base64. + /// + /// Default implementation returns false as JSON does not + /// support native access: all binary content must use Base64 encoding. + /// Most binary formats (like Smile and Avro) support native binary content. + ///@return Whether format supported by this factory + /// supports native binary content + ///@since 2.3 + bool canHandleBinaryNatively() { + return jni.Jni.accessors.callMethodWithArgs(reference, + _id_canHandleBinaryNatively, jni.JniCallType.booleanType, []).boolean; + } + + static final _id_canUseCharArrays = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"canUseCharArrays", r"()Z"); + + /// from: public boolean canUseCharArrays() + /// + /// Introspection method that can be used by base factory to check + /// whether access using char[] is something that actual + /// parser implementations can take advantage of, over having to + /// use java.io.Reader. Sub-types are expected to override + /// definition; default implementation (suitable for JSON) alleges + /// that optimization are possible; and thereby is likely to try + /// to access java.lang.String content by first copying it into + /// recyclable intermediate buffer. + ///@return Whether access to decoded textual content can be efficiently + /// accessed using parser method {@code getTextCharacters()}. + ///@since 2.4 + bool canUseCharArrays() { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_canUseCharArrays, + jni.JniCallType.booleanType, []).boolean; + } + + static final _id_canParseAsync = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"canParseAsync", r"()Z"); + + /// from: public boolean canParseAsync() + /// + /// Introspection method that can be used to check whether this + /// factory can create non-blocking parsers: parsers that do not + /// use blocking I/O abstractions but instead use a + /// com.fasterxml.jackson.core.async.NonBlockingInputFeeder. + ///@return Whether this factory supports non-blocking ("async") parsing or + /// not (and consequently whether {@code createNonBlockingXxx()} method(s) work) + ///@since 2.9 + bool canParseAsync() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_canParseAsync, jni.JniCallType.booleanType, []).boolean; + } + + static final _id_getFormatReadFeatureType = jni.Jni.accessors.getMethodIDOf( + _class.reference, r"getFormatReadFeatureType", r"()Ljava/lang/Class;"); + + /// from: public java.lang.Class getFormatReadFeatureType() + /// The returned object must be released after use, by calling the [release] method. + jni.JObject getFormatReadFeatureType() { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_getFormatReadFeatureType, + jni.JniCallType.objectType, []).object); + } + + static final _id_getFormatWriteFeatureType = jni.Jni.accessors.getMethodIDOf( + _class.reference, r"getFormatWriteFeatureType", r"()Ljava/lang/Class;"); + + /// from: public java.lang.Class getFormatWriteFeatureType() + /// The returned object must be released after use, by calling the [release] method. + jni.JObject getFormatWriteFeatureType() { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_getFormatWriteFeatureType, + jni.JniCallType.objectType, []).object); + } + + static final _id_canUseSchema = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"canUseSchema", + r"(Lcom/fasterxml/jackson/core/FormatSchema;)Z"); + + /// from: public boolean canUseSchema(com.fasterxml.jackson.core.FormatSchema schema) + /// + /// Method that can be used to quickly check whether given schema + /// is something that parsers and/or generators constructed by this + /// factory could use. Note that this means possible use, at the level + /// of data format (i.e. schema is for same data format as parsers and + /// generators this factory constructs); individual schema instances + /// may have further usage restrictions. + ///@param schema Schema instance to check + ///@return Whether parsers and generators constructed by this factory + /// can use specified format schema instance + bool canUseSchema( + jni.JObject schema, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_canUseSchema, + jni.JniCallType.booleanType, [schema.reference]).boolean; + } + + static final _id_getFormatName = jni.Jni.accessors.getMethodIDOf( + _class.reference, r"getFormatName", r"()Ljava/lang/String;"); + + /// from: public java.lang.String getFormatName() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that returns short textual id identifying format + /// this factory supports. + /// + /// Note: sub-classes should override this method; default + /// implementation will return null for all sub-classes + ///@return Name of the format handled by parsers, generators this factory creates + jni.JString getFormatName() { + return const jni.JStringType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, _id_getFormatName, jni.JniCallType.objectType, []).object); + } + + static final _id_hasFormat = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"hasFormat", + r"(Lcom/fasterxml/jackson/core/format/InputAccessor;)Lcom/fasterxml/jackson/core/format/MatchStrength;"); + + /// from: public com.fasterxml.jackson.core.format.MatchStrength hasFormat(com.fasterxml.jackson.core.format.InputAccessor acc) + /// The returned object must be released after use, by calling the [release] method. + jni.JObject hasFormat( + jni.JObject acc, + ) { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_hasFormat, + jni.JniCallType.objectType, + [acc.reference]).object); + } + + static final _id_requiresCustomCodec = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"requiresCustomCodec", r"()Z"); + + /// from: public boolean requiresCustomCodec() + /// + /// Method that can be called to determine if a custom + /// ObjectCodec is needed for binding data parsed + /// using JsonParser constructed by this factory + /// (which typically also implies the same for serialization + /// with JsonGenerator). + ///@return True if custom codec is needed with parsers and + /// generators created by this factory; false if a general + /// ObjectCodec is enough + ///@since 2.1 + bool requiresCustomCodec() { + return jni.Jni.accessors.callMethodWithArgs(reference, + _id_requiresCustomCodec, jni.JniCallType.booleanType, []).boolean; + } + + static final _id_hasJSONFormat = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"hasJSONFormat", + r"(Lcom/fasterxml/jackson/core/format/InputAccessor;)Lcom/fasterxml/jackson/core/format/MatchStrength;"); + + /// from: protected com.fasterxml.jackson.core.format.MatchStrength hasJSONFormat(com.fasterxml.jackson.core.format.InputAccessor acc) + /// The returned object must be released after use, by calling the [release] method. + jni.JObject hasJSONFormat( + jni.JObject acc, + ) { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_hasJSONFormat, + jni.JniCallType.objectType, + [acc.reference]).object); + } + + static final _id_version = jni.Jni.accessors.getMethodIDOf( + _class.reference, r"version", r"()Lcom/fasterxml/jackson/core/Version;"); + + /// from: public com.fasterxml.jackson.core.Version version() + /// The returned object must be released after use, by calling the [release] method. + jni.JObject version() { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, _id_version, jni.JniCallType.objectType, []).object); + } + + static final _id_configure = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"configure", + r"(Lcom/fasterxml/jackson/core/JsonFactory$Feature;Z)Lcom/fasterxml/jackson/core/JsonFactory;"); + + /// from: public final com.fasterxml.jackson.core.JsonFactory configure(com.fasterxml.jackson.core.JsonFactory.Feature f, boolean state) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for enabling or disabling specified parser feature + /// (check JsonParser.Feature for list of features) + ///@param f Feature to enable/disable + ///@param state Whether to enable or disable the feature + ///@return This factory instance (to allow call chaining) + ///@deprecated since 2.10 use JsonFactoryBuilder\#configure(JsonFactory.Feature, boolean) instead + JsonFactory configure( + JsonFactory_Feature f, + bool state, + ) { + return const $JsonFactoryType().fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_configure, + jni.JniCallType.objectType, [f.reference, state ? 1 : 0]).object); + } + + static final _id_enable = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"enable", + r"(Lcom/fasterxml/jackson/core/JsonFactory$Feature;)Lcom/fasterxml/jackson/core/JsonFactory;"); + + /// from: public com.fasterxml.jackson.core.JsonFactory enable(com.fasterxml.jackson.core.JsonFactory.Feature f) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for enabling specified parser feature + /// (check JsonFactory.Feature for list of features) + ///@param f Feature to enable + ///@return This factory instance (to allow call chaining) + ///@deprecated since 2.10 use JsonFactoryBuilder\#configure(JsonFactory.Feature, boolean) instead + JsonFactory enable( + JsonFactory_Feature f, + ) { + return const $JsonFactoryType().fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_enable, jni.JniCallType.objectType, + [f.reference]).object); + } + + static final _id_disable = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"disable", + r"(Lcom/fasterxml/jackson/core/JsonFactory$Feature;)Lcom/fasterxml/jackson/core/JsonFactory;"); + + /// from: public com.fasterxml.jackson.core.JsonFactory disable(com.fasterxml.jackson.core.JsonFactory.Feature f) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for disabling specified parser features + /// (check JsonFactory.Feature for list of features) + ///@param f Feature to disable + ///@return This factory instance (to allow call chaining) + ///@deprecated since 2.10 use JsonFactoryBuilder\#configure(JsonFactory.Feature, boolean) instead + JsonFactory disable( + JsonFactory_Feature f, + ) { + return const $JsonFactoryType().fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_disable, jni.JniCallType.objectType, + [f.reference]).object); + } + + static final _id_isEnabled = jni.Jni.accessors.getMethodIDOf(_class.reference, + r"isEnabled", r"(Lcom/fasterxml/jackson/core/JsonFactory$Feature;)Z"); + + /// from: public final boolean isEnabled(com.fasterxml.jackson.core.JsonFactory.Feature f) + /// + /// Checked whether specified parser feature is enabled. + ///@param f Feature to check + ///@return True if the specified feature is enabled + bool isEnabled( + JsonFactory_Feature f, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_isEnabled, + jni.JniCallType.booleanType, [f.reference]).boolean; + } + + static final _id_getParserFeatures = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"getParserFeatures", r"()I"); + + /// from: public final int getParserFeatures() + int getParserFeatures() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_getParserFeatures, jni.JniCallType.intType, []).integer; + } + + static final _id_getGeneratorFeatures = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"getGeneratorFeatures", r"()I"); + + /// from: public final int getGeneratorFeatures() + int getGeneratorFeatures() { + return jni.Jni.accessors.callMethodWithArgs(reference, + _id_getGeneratorFeatures, jni.JniCallType.intType, []).integer; + } + + static final _id_getFormatParserFeatures = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"getFormatParserFeatures", r"()I"); + + /// from: public int getFormatParserFeatures() + int getFormatParserFeatures() { + return jni.Jni.accessors.callMethodWithArgs(reference, + _id_getFormatParserFeatures, jni.JniCallType.intType, []).integer; + } + + static final _id_getFormatGeneratorFeatures = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"getFormatGeneratorFeatures", r"()I"); + + /// from: public int getFormatGeneratorFeatures() + int getFormatGeneratorFeatures() { + return jni.Jni.accessors.callMethodWithArgs(reference, + _id_getFormatGeneratorFeatures, jni.JniCallType.intType, []).integer; + } + + static final _id_configure1 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"configure", + r"(Lcom/fasterxml/jackson/core/JsonParser$Feature;Z)Lcom/fasterxml/jackson/core/JsonFactory;"); + + /// from: public final com.fasterxml.jackson.core.JsonFactory configure(com.fasterxml.jackson.core.JsonParser.Feature f, boolean state) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for enabling or disabling specified parser feature + /// (check JsonParser.Feature for list of features) + ///@param f Feature to enable/disable + ///@param state Whether to enable or disable the feature + ///@return This factory instance (to allow call chaining) + JsonFactory configure1( + jsonparser_.JsonParser_Feature f, + bool state, + ) { + return const $JsonFactoryType().fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_configure1, + jni.JniCallType.objectType, [f.reference, state ? 1 : 0]).object); + } + + static final _id_enable1 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"enable", + r"(Lcom/fasterxml/jackson/core/JsonParser$Feature;)Lcom/fasterxml/jackson/core/JsonFactory;"); + + /// from: public com.fasterxml.jackson.core.JsonFactory enable(com.fasterxml.jackson.core.JsonParser.Feature f) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for enabling specified parser feature + /// (check JsonParser.Feature for list of features) + ///@param f Feature to enable + ///@return This factory instance (to allow call chaining) + JsonFactory enable1( + jsonparser_.JsonParser_Feature f, + ) { + return const $JsonFactoryType().fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_enable1, jni.JniCallType.objectType, + [f.reference]).object); + } + + static final _id_disable1 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"disable", + r"(Lcom/fasterxml/jackson/core/JsonParser$Feature;)Lcom/fasterxml/jackson/core/JsonFactory;"); + + /// from: public com.fasterxml.jackson.core.JsonFactory disable(com.fasterxml.jackson.core.JsonParser.Feature f) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for disabling specified parser features + /// (check JsonParser.Feature for list of features) + ///@param f Feature to disable + ///@return This factory instance (to allow call chaining) + JsonFactory disable1( + jsonparser_.JsonParser_Feature f, + ) { + return const $JsonFactoryType().fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_disable1, jni.JniCallType.objectType, + [f.reference]).object); + } + + static final _id_isEnabled1 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"isEnabled", + r"(Lcom/fasterxml/jackson/core/JsonParser$Feature;)Z"); + + /// from: public final boolean isEnabled(com.fasterxml.jackson.core.JsonParser.Feature f) + /// + /// Method for checking if the specified parser feature is enabled. + ///@param f Feature to check + ///@return True if specified feature is enabled + bool isEnabled1( + jsonparser_.JsonParser_Feature f, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_isEnabled1, + jni.JniCallType.booleanType, [f.reference]).boolean; + } + + static final _id_isEnabled2 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"isEnabled", + r"(Lcom/fasterxml/jackson/core/StreamReadFeature;)Z"); + + /// from: public final boolean isEnabled(com.fasterxml.jackson.core.StreamReadFeature f) + /// + /// Method for checking if the specified stream read feature is enabled. + ///@param f Feature to check + ///@return True if specified feature is enabled + ///@since 2.10 + bool isEnabled2( + jni.JObject f, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_isEnabled2, + jni.JniCallType.booleanType, [f.reference]).boolean; + } + + static final _id_getInputDecorator = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"getInputDecorator", + r"()Lcom/fasterxml/jackson/core/io/InputDecorator;"); + + /// from: public com.fasterxml.jackson.core.io.InputDecorator getInputDecorator() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for getting currently configured input decorator (if any; + /// there is no default decorator). + ///@return InputDecorator configured, if any + jni.JObject getInputDecorator() { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_getInputDecorator, + jni.JniCallType.objectType, []).object); + } + + static final _id_setInputDecorator = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"setInputDecorator", + r"(Lcom/fasterxml/jackson/core/io/InputDecorator;)Lcom/fasterxml/jackson/core/JsonFactory;"); + + /// from: public com.fasterxml.jackson.core.JsonFactory setInputDecorator(com.fasterxml.jackson.core.io.InputDecorator d) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for overriding currently configured input decorator + ///@param d Decorator to configure for this factory, if any ({@code null} if none) + ///@return This factory instance (to allow call chaining) + ///@deprecated Since 2.10 use JsonFactoryBuilder\#inputDecorator(InputDecorator) instead + JsonFactory setInputDecorator( + jni.JObject d, + ) { + return const $JsonFactoryType().fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_setInputDecorator, + jni.JniCallType.objectType, [d.reference]).object); + } + + static final _id_configure2 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"configure", + r"(Lcom/fasterxml/jackson/core/JsonGenerator$Feature;Z)Lcom/fasterxml/jackson/core/JsonFactory;"); + + /// from: public final com.fasterxml.jackson.core.JsonFactory configure(com.fasterxml.jackson.core.JsonGenerator.Feature f, boolean state) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for enabling or disabling specified generator feature + /// (check JsonGenerator.Feature for list of features) + ///@param f Feature to enable/disable + ///@param state Whether to enable or disable the feature + ///@return This factory instance (to allow call chaining) + JsonFactory configure2( + jni.JObject f, + bool state, + ) { + return const $JsonFactoryType().fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_configure2, + jni.JniCallType.objectType, [f.reference, state ? 1 : 0]).object); + } + + static final _id_enable2 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"enable", + r"(Lcom/fasterxml/jackson/core/JsonGenerator$Feature;)Lcom/fasterxml/jackson/core/JsonFactory;"); + + /// from: public com.fasterxml.jackson.core.JsonFactory enable(com.fasterxml.jackson.core.JsonGenerator.Feature f) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for enabling specified generator features + /// (check JsonGenerator.Feature for list of features) + ///@param f Feature to enable + ///@return This factory instance (to allow call chaining) + JsonFactory enable2( + jni.JObject f, + ) { + return const $JsonFactoryType().fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_enable2, jni.JniCallType.objectType, + [f.reference]).object); + } + + static final _id_disable2 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"disable", + r"(Lcom/fasterxml/jackson/core/JsonGenerator$Feature;)Lcom/fasterxml/jackson/core/JsonFactory;"); + + /// from: public com.fasterxml.jackson.core.JsonFactory disable(com.fasterxml.jackson.core.JsonGenerator.Feature f) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for disabling specified generator feature + /// (check JsonGenerator.Feature for list of features) + ///@param f Feature to disable + ///@return This factory instance (to allow call chaining) + JsonFactory disable2( + jni.JObject f, + ) { + return const $JsonFactoryType().fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_disable2, jni.JniCallType.objectType, + [f.reference]).object); + } + + static final _id_isEnabled3 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"isEnabled", + r"(Lcom/fasterxml/jackson/core/JsonGenerator$Feature;)Z"); + + /// from: public final boolean isEnabled(com.fasterxml.jackson.core.JsonGenerator.Feature f) + /// + /// Check whether specified generator feature is enabled. + ///@param f Feature to check + ///@return Whether specified feature is enabled + bool isEnabled3( + jni.JObject f, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_isEnabled3, + jni.JniCallType.booleanType, [f.reference]).boolean; + } + + static final _id_isEnabled4 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"isEnabled", + r"(Lcom/fasterxml/jackson/core/StreamWriteFeature;)Z"); + + /// from: public final boolean isEnabled(com.fasterxml.jackson.core.StreamWriteFeature f) + /// + /// Check whether specified stream write feature is enabled. + ///@param f Feature to check + ///@return Whether specified feature is enabled + ///@since 2.10 + bool isEnabled4( + jni.JObject f, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_isEnabled4, + jni.JniCallType.booleanType, [f.reference]).boolean; + } + + static final _id_getCharacterEscapes = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"getCharacterEscapes", + r"()Lcom/fasterxml/jackson/core/io/CharacterEscapes;"); + + /// from: public com.fasterxml.jackson.core.io.CharacterEscapes getCharacterEscapes() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for accessing custom escapes factory uses for JsonGenerators + /// it creates. + ///@return Configured {@code CharacterEscapes}, if any; {@code null} if none + jni.JObject getCharacterEscapes() { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_getCharacterEscapes, + jni.JniCallType.objectType, []).object); + } + + static final _id_setCharacterEscapes = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"setCharacterEscapes", + r"(Lcom/fasterxml/jackson/core/io/CharacterEscapes;)Lcom/fasterxml/jackson/core/JsonFactory;"); + + /// from: public com.fasterxml.jackson.core.JsonFactory setCharacterEscapes(com.fasterxml.jackson.core.io.CharacterEscapes esc) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for defining custom escapes factory uses for JsonGenerators + /// it creates. + ///@param esc CharaterEscapes to set (or {@code null} for "none") + ///@return This factory instance (to allow call chaining) + JsonFactory setCharacterEscapes( + jni.JObject esc, + ) { + return const $JsonFactoryType().fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_setCharacterEscapes, + jni.JniCallType.objectType, [esc.reference]).object); + } + + static final _id_getOutputDecorator = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"getOutputDecorator", + r"()Lcom/fasterxml/jackson/core/io/OutputDecorator;"); + + /// from: public com.fasterxml.jackson.core.io.OutputDecorator getOutputDecorator() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for getting currently configured output decorator (if any; + /// there is no default decorator). + ///@return OutputDecorator configured for generators factory creates, if any; + /// {@code null} if none. + jni.JObject getOutputDecorator() { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_getOutputDecorator, + jni.JniCallType.objectType, []).object); + } + + static final _id_setOutputDecorator = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"setOutputDecorator", + r"(Lcom/fasterxml/jackson/core/io/OutputDecorator;)Lcom/fasterxml/jackson/core/JsonFactory;"); + + /// from: public com.fasterxml.jackson.core.JsonFactory setOutputDecorator(com.fasterxml.jackson.core.io.OutputDecorator d) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for overriding currently configured output decorator + ///@return This factory instance (to allow call chaining) + ///@param d Output decorator to use, if any + ///@deprecated Since 2.10 use JsonFactoryBuilder\#outputDecorator(OutputDecorator) instead + JsonFactory setOutputDecorator( + jni.JObject d, + ) { + return const $JsonFactoryType().fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_setOutputDecorator, + jni.JniCallType.objectType, [d.reference]).object); + } + + static final _id_setRootValueSeparator = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"setRootValueSeparator", + r"(Ljava/lang/String;)Lcom/fasterxml/jackson/core/JsonFactory;"); + + /// from: public com.fasterxml.jackson.core.JsonFactory setRootValueSeparator(java.lang.String sep) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that allows overriding String used for separating root-level + /// JSON values (default is single space character) + ///@param sep Separator to use, if any; null means that no separator is + /// automatically added + ///@return This factory instance (to allow call chaining) + JsonFactory setRootValueSeparator( + jni.JString sep, + ) { + return const $JsonFactoryType().fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_setRootValueSeparator, + jni.JniCallType.objectType, [sep.reference]).object); + } + + static final _id_getRootValueSeparator = jni.Jni.accessors.getMethodIDOf( + _class.reference, r"getRootValueSeparator", r"()Ljava/lang/String;"); + + /// from: public java.lang.String getRootValueSeparator() + /// The returned object must be released after use, by calling the [release] method. + /// + /// @return Root value separator configured, if any + jni.JString getRootValueSeparator() { + return const jni.JStringType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_getRootValueSeparator, + jni.JniCallType.objectType, []).object); + } + + static final _id_setCodec = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"setCodec", + r"(Lcom/fasterxml/jackson/core/ObjectCodec;)Lcom/fasterxml/jackson/core/JsonFactory;"); + + /// from: public com.fasterxml.jackson.core.JsonFactory setCodec(com.fasterxml.jackson.core.ObjectCodec oc) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for associating a ObjectCodec (typically + /// a com.fasterxml.jackson.databind.ObjectMapper) + /// with this factory (and more importantly, parsers and generators + /// it constructs). This is needed to use data-binding methods + /// of JsonParser and JsonGenerator instances. + ///@param oc Codec to use + ///@return This factory instance (to allow call chaining) + JsonFactory setCodec( + jni.JObject oc, + ) { + return const $JsonFactoryType().fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_setCodec, jni.JniCallType.objectType, + [oc.reference]).object); + } + + static final _id_getCodec = jni.Jni.accessors.getMethodIDOf(_class.reference, + r"getCodec", r"()Lcom/fasterxml/jackson/core/ObjectCodec;"); + + /// from: public com.fasterxml.jackson.core.ObjectCodec getCodec() + /// The returned object must be released after use, by calling the [release] method. + jni.JObject getCodec() { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, _id_getCodec, jni.JniCallType.objectType, []).object); + } + + static final _id_createParser = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"createParser", + r"(Ljava/io/File;)Lcom/fasterxml/jackson/core/JsonParser;"); + + /// from: public com.fasterxml.jackson.core.JsonParser createParser(java.io.File f) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing JSON parser instance to parse + /// contents of specified file. + /// + /// + /// Encoding is auto-detected from contents according to JSON + /// specification recommended mechanism. Json specification + /// supports only UTF-8, UTF-16 and UTF-32 as valid encodings, + /// so auto-detection implemented only for this charsets. + /// For other charsets use \#createParser(java.io.Reader). + /// + /// + /// Underlying input stream (needed for reading contents) + /// will be __owned__ (and managed, i.e. closed as need be) by + /// the parser, since caller has no access to it. + ///@param f File that contains JSON content to parse + ///@since 2.1 + jsonparser_.JsonParser createParser( + jni.JObject f, + ) { + return const jsonparser_.$JsonParserType().fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_createParser, + jni.JniCallType.objectType, [f.reference]).object); + } + + static final _id_createParser1 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"createParser", + r"(Ljava/net/URL;)Lcom/fasterxml/jackson/core/JsonParser;"); + + /// from: public com.fasterxml.jackson.core.JsonParser createParser(java.net.URL url) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing JSON parser instance to parse + /// contents of resource reference by given URL. + /// + /// Encoding is auto-detected from contents according to JSON + /// specification recommended mechanism. Json specification + /// supports only UTF-8, UTF-16 and UTF-32 as valid encodings, + /// so auto-detection implemented only for this charsets. + /// For other charsets use \#createParser(java.io.Reader). + /// + /// Underlying input stream (needed for reading contents) + /// will be __owned__ (and managed, i.e. closed as need be) by + /// the parser, since caller has no access to it. + ///@param url URL pointing to resource that contains JSON content to parse + ///@since 2.1 + jsonparser_.JsonParser createParser1( + jni.JObject url, + ) { + return const jsonparser_.$JsonParserType().fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_createParser1, + jni.JniCallType.objectType, [url.reference]).object); + } + + static final _id_createParser2 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"createParser", + r"(Ljava/io/InputStream;)Lcom/fasterxml/jackson/core/JsonParser;"); + + /// from: public com.fasterxml.jackson.core.JsonParser createParser(java.io.InputStream in) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing JSON parser instance to parse + /// the contents accessed via specified input stream. + /// + /// The input stream will __not be owned__ by + /// the parser, it will still be managed (i.e. closed if + /// end-of-stream is reacher, or parser close method called) + /// if (and only if) com.fasterxml.jackson.core.StreamReadFeature\#AUTO_CLOSE_SOURCE + /// is enabled. + /// + /// + /// Note: no encoding argument is taken since it can always be + /// auto-detected as suggested by JSON RFC. Json specification + /// supports only UTF-8, UTF-16 and UTF-32 as valid encodings, + /// so auto-detection implemented only for this charsets. + /// For other charsets use \#createParser(java.io.Reader). + ///@param in InputStream to use for reading JSON content to parse + ///@since 2.1 + jsonparser_.JsonParser createParser2( + jni.JObject in0, + ) { + return const jsonparser_.$JsonParserType().fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_createParser2, + jni.JniCallType.objectType, [in0.reference]).object); + } + + static final _id_createParser3 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"createParser", + r"(Ljava/io/Reader;)Lcom/fasterxml/jackson/core/JsonParser;"); + + /// from: public com.fasterxml.jackson.core.JsonParser createParser(java.io.Reader r) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing parser for parsing + /// the contents accessed via specified Reader. + /// + /// The read stream will __not be owned__ by + /// the parser, it will still be managed (i.e. closed if + /// end-of-stream is reacher, or parser close method called) + /// if (and only if) com.fasterxml.jackson.core.StreamReadFeature\#AUTO_CLOSE_SOURCE + /// is enabled. + ///@param r Reader to use for reading JSON content to parse + ///@since 2.1 + jsonparser_.JsonParser createParser3( + jni.JObject r, + ) { + return const jsonparser_.$JsonParserType().fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_createParser3, + jni.JniCallType.objectType, [r.reference]).object); + } + + static final _id_createParser4 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"createParser", + r"([B)Lcom/fasterxml/jackson/core/JsonParser;"); + + /// from: public com.fasterxml.jackson.core.JsonParser createParser(byte[] data) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing parser for parsing + /// the contents of given byte array. + ///@since 2.1 + jsonparser_.JsonParser createParser4( + jni.JArray data, + ) { + return const jsonparser_.$JsonParserType().fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_createParser4, + jni.JniCallType.objectType, [data.reference]).object); + } + + static final _id_createParser5 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"createParser", + r"([BII)Lcom/fasterxml/jackson/core/JsonParser;"); + + /// from: public com.fasterxml.jackson.core.JsonParser createParser(byte[] data, int offset, int len) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing parser for parsing + /// the contents of given byte array. + ///@param data Buffer that contains data to parse + ///@param offset Offset of the first data byte within buffer + ///@param len Length of contents to parse within buffer + ///@since 2.1 + jsonparser_.JsonParser createParser5( + jni.JArray data, + int offset, + int len, + ) { + return const jsonparser_.$JsonParserType().fromRef(jni.Jni.accessors + .callMethodWithArgs( + reference, _id_createParser5, jni.JniCallType.objectType, [ + data.reference, + jni.JValueInt(offset), + jni.JValueInt(len) + ]).object); + } + + static final _id_createParser6 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"createParser", + r"(Ljava/lang/String;)Lcom/fasterxml/jackson/core/JsonParser;"); + + /// from: public com.fasterxml.jackson.core.JsonParser createParser(java.lang.String content) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing parser for parsing + /// contents of given String. + ///@since 2.1 + jsonparser_.JsonParser createParser6( + jni.JString content, + ) { + return const jsonparser_.$JsonParserType().fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_createParser6, + jni.JniCallType.objectType, [content.reference]).object); + } + + static final _id_createParser7 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"createParser", + r"([C)Lcom/fasterxml/jackson/core/JsonParser;"); + + /// from: public com.fasterxml.jackson.core.JsonParser createParser(char[] content) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing parser for parsing + /// contents of given char array. + ///@since 2.4 + jsonparser_.JsonParser createParser7( + jni.JArray content, + ) { + return const jsonparser_.$JsonParserType().fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_createParser7, + jni.JniCallType.objectType, [content.reference]).object); + } + + static final _id_createParser8 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"createParser", + r"([CII)Lcom/fasterxml/jackson/core/JsonParser;"); + + /// from: public com.fasterxml.jackson.core.JsonParser createParser(char[] content, int offset, int len) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing parser for parsing contents of given char array. + ///@since 2.4 + jsonparser_.JsonParser createParser8( + jni.JArray content, + int offset, + int len, + ) { + return const jsonparser_.$JsonParserType().fromRef(jni.Jni.accessors + .callMethodWithArgs( + reference, _id_createParser8, jni.JniCallType.objectType, [ + content.reference, + jni.JValueInt(offset), + jni.JValueInt(len) + ]).object); + } + + static final _id_createParser9 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"createParser", + r"(Ljava/io/DataInput;)Lcom/fasterxml/jackson/core/JsonParser;"); + + /// from: public com.fasterxml.jackson.core.JsonParser createParser(java.io.DataInput in) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Optional method for constructing parser for reading contents from specified DataInput + /// instance. + /// + /// If this factory does not support DataInput as source, + /// will throw UnsupportedOperationException + ///@since 2.8 + jsonparser_.JsonParser createParser9( + jni.JObject in0, + ) { + return const jsonparser_.$JsonParserType().fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_createParser9, + jni.JniCallType.objectType, [in0.reference]).object); + } + + static final _id_createNonBlockingByteArrayParser = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"createNonBlockingByteArrayParser", + r"()Lcom/fasterxml/jackson/core/JsonParser;"); + + /// from: public com.fasterxml.jackson.core.JsonParser createNonBlockingByteArrayParser() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Optional method for constructing parser for non-blocking parsing + /// via com.fasterxml.jackson.core.async.ByteArrayFeeder + /// interface (accessed using JsonParser\#getNonBlockingInputFeeder() + /// from constructed instance). + /// + /// If this factory does not support non-blocking parsing (either at all, + /// or from byte array), + /// will throw UnsupportedOperationException. + /// + /// Note that JSON-backed factory only supports parsing of UTF-8 encoded JSON content + /// (and US-ASCII since it is proper subset); other encodings are not supported + /// at this point. + ///@since 2.9 + jsonparser_.JsonParser createNonBlockingByteArrayParser() { + return const jsonparser_.$JsonParserType().fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_createNonBlockingByteArrayParser, + jni.JniCallType.objectType, []).object); + } + + static final _id_createGenerator = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"createGenerator", + r"(Ljava/io/OutputStream;Lcom/fasterxml/jackson/core/JsonEncoding;)Lcom/fasterxml/jackson/core/JsonGenerator;"); + + /// from: public com.fasterxml.jackson.core.JsonGenerator createGenerator(java.io.OutputStream out, com.fasterxml.jackson.core.JsonEncoding enc) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing JSON generator for writing JSON content + /// using specified output stream. + /// Encoding to use must be specified, and needs to be one of available + /// types (as per JSON specification). + /// + /// Underlying stream __is NOT owned__ by the generator constructed, + /// so that generator will NOT close the output stream when + /// JsonGenerator\#close is called (unless auto-closing + /// feature, + /// com.fasterxml.jackson.core.JsonGenerator.Feature\#AUTO_CLOSE_TARGET + /// is enabled). + /// Using application needs to close it explicitly if this is the case. + /// + /// Note: there are formats that use fixed encoding (like most binary data formats) + /// and that ignore passed in encoding. + ///@param out OutputStream to use for writing JSON content + ///@param enc Character encoding to use + ///@since 2.1 + jni.JObject createGenerator( + jni.JObject out, + jni.JObject enc, + ) { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_createGenerator, + jni.JniCallType.objectType, + [out.reference, enc.reference]).object); + } + + static final _id_createGenerator1 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"createGenerator", + r"(Ljava/io/OutputStream;)Lcom/fasterxml/jackson/core/JsonGenerator;"); + + /// from: public com.fasterxml.jackson.core.JsonGenerator createGenerator(java.io.OutputStream out) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Convenience method for constructing generator that uses default + /// encoding of the format (UTF-8 for JSON and most other data formats). + /// + /// Note: there are formats that use fixed encoding (like most binary data formats). + ///@since 2.1 + jni.JObject createGenerator1( + jni.JObject out, + ) { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_createGenerator1, + jni.JniCallType.objectType, + [out.reference]).object); + } + + static final _id_createGenerator2 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"createGenerator", + r"(Ljava/io/Writer;)Lcom/fasterxml/jackson/core/JsonGenerator;"); + + /// from: public com.fasterxml.jackson.core.JsonGenerator createGenerator(java.io.Writer w) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing JSON generator for writing JSON content + /// using specified Writer. + /// + /// Underlying stream __is NOT owned__ by the generator constructed, + /// so that generator will NOT close the Reader when + /// JsonGenerator\#close is called (unless auto-closing + /// feature, + /// com.fasterxml.jackson.core.JsonGenerator.Feature\#AUTO_CLOSE_TARGET is enabled). + /// Using application needs to close it explicitly. + ///@since 2.1 + ///@param w Writer to use for writing JSON content + jni.JObject createGenerator2( + jni.JObject w, + ) { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_createGenerator2, + jni.JniCallType.objectType, + [w.reference]).object); + } + + static final _id_createGenerator3 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"createGenerator", + r"(Ljava/io/File;Lcom/fasterxml/jackson/core/JsonEncoding;)Lcom/fasterxml/jackson/core/JsonGenerator;"); + + /// from: public com.fasterxml.jackson.core.JsonGenerator createGenerator(java.io.File f, com.fasterxml.jackson.core.JsonEncoding enc) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing JSON generator for writing JSON content + /// to specified file, overwriting contents it might have (or creating + /// it if such file does not yet exist). + /// Encoding to use must be specified, and needs to be one of available + /// types (as per JSON specification). + /// + /// Underlying stream __is owned__ by the generator constructed, + /// i.e. generator will handle closing of file when + /// JsonGenerator\#close is called. + ///@param f File to write contents to + ///@param enc Character encoding to use + ///@since 2.1 + jni.JObject createGenerator3( + jni.JObject f, + jni.JObject enc, + ) { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_createGenerator3, + jni.JniCallType.objectType, + [f.reference, enc.reference]).object); + } + + static final _id_createGenerator4 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"createGenerator", + r"(Ljava/io/DataOutput;Lcom/fasterxml/jackson/core/JsonEncoding;)Lcom/fasterxml/jackson/core/JsonGenerator;"); + + /// from: public com.fasterxml.jackson.core.JsonGenerator createGenerator(java.io.DataOutput out, com.fasterxml.jackson.core.JsonEncoding enc) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing generator for writing content using specified + /// DataOutput instance. + ///@since 2.8 + jni.JObject createGenerator4( + jni.JObject out, + jni.JObject enc, + ) { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_createGenerator4, + jni.JniCallType.objectType, + [out.reference, enc.reference]).object); + } + + static final _id_createGenerator5 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"createGenerator", + r"(Ljava/io/DataOutput;)Lcom/fasterxml/jackson/core/JsonGenerator;"); + + /// from: public com.fasterxml.jackson.core.JsonGenerator createGenerator(java.io.DataOutput out) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Convenience method for constructing generator that uses default + /// encoding of the format (UTF-8 for JSON and most other data formats). + /// + /// Note: there are formats that use fixed encoding (like most binary data formats). + ///@since 2.8 + jni.JObject createGenerator5( + jni.JObject out, + ) { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_createGenerator5, + jni.JniCallType.objectType, + [out.reference]).object); + } + + static final _id_createJsonParser = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"createJsonParser", + r"(Ljava/io/File;)Lcom/fasterxml/jackson/core/JsonParser;"); + + /// from: public com.fasterxml.jackson.core.JsonParser createJsonParser(java.io.File f) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing JSON parser instance to parse + /// contents of specified file. + /// + /// Encoding is auto-detected from contents according to JSON + /// specification recommended mechanism. Json specification + /// supports only UTF-8, UTF-16 and UTF-32 as valid encodings, + /// so auto-detection implemented only for this charsets. + /// For other charsets use \#createParser(java.io.Reader). + /// + /// + /// Underlying input stream (needed for reading contents) + /// will be __owned__ (and managed, i.e. closed as need be) by + /// the parser, since caller has no access to it. + ///@param f File that contains JSON content to parse + ///@return Parser constructed + ///@throws IOException if parser initialization fails due to I/O (read) problem + ///@throws JsonParseException if parser initialization fails due to content decoding problem + ///@deprecated Since 2.2, use \#createParser(File) instead. + jsonparser_.JsonParser createJsonParser( + jni.JObject f, + ) { + return const jsonparser_.$JsonParserType().fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_createJsonParser, + jni.JniCallType.objectType, [f.reference]).object); + } + + static final _id_createJsonParser1 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"createJsonParser", + r"(Ljava/net/URL;)Lcom/fasterxml/jackson/core/JsonParser;"); + + /// from: public com.fasterxml.jackson.core.JsonParser createJsonParser(java.net.URL url) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing JSON parser instance to parse + /// contents of resource reference by given URL. + /// + /// Encoding is auto-detected from contents according to JSON + /// specification recommended mechanism. Json specification + /// supports only UTF-8, UTF-16 and UTF-32 as valid encodings, + /// so auto-detection implemented only for this charsets. + /// For other charsets use \#createParser(java.io.Reader). + /// + /// Underlying input stream (needed for reading contents) + /// will be __owned__ (and managed, i.e. closed as need be) by + /// the parser, since caller has no access to it. + ///@param url URL pointing to resource that contains JSON content to parse + ///@return Parser constructed + ///@throws IOException if parser initialization fails due to I/O (read) problem + ///@throws JsonParseException if parser initialization fails due to content decoding problem + ///@deprecated Since 2.2, use \#createParser(URL) instead. + jsonparser_.JsonParser createJsonParser1( + jni.JObject url, + ) { + return const jsonparser_.$JsonParserType().fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_createJsonParser1, + jni.JniCallType.objectType, [url.reference]).object); + } + + static final _id_createJsonParser2 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"createJsonParser", + r"(Ljava/io/InputStream;)Lcom/fasterxml/jackson/core/JsonParser;"); + + /// from: public com.fasterxml.jackson.core.JsonParser createJsonParser(java.io.InputStream in) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing JSON parser instance to parse + /// the contents accessed via specified input stream. + /// + /// The input stream will __not be owned__ by + /// the parser, it will still be managed (i.e. closed if + /// end-of-stream is reacher, or parser close method called) + /// if (and only if) com.fasterxml.jackson.core.JsonParser.Feature\#AUTO_CLOSE_SOURCE + /// is enabled. + /// + /// + /// Note: no encoding argument is taken since it can always be + /// auto-detected as suggested by JSON RFC. Json specification + /// supports only UTF-8, UTF-16 and UTF-32 as valid encodings, + /// so auto-detection implemented only for this charsets. + /// For other charsets use \#createParser(java.io.Reader). + ///@param in InputStream to use for reading JSON content to parse + ///@return Parser constructed + ///@throws IOException if parser initialization fails due to I/O (read) problem + ///@throws JsonParseException if parser initialization fails due to content decoding problem + ///@deprecated Since 2.2, use \#createParser(InputStream) instead. + jsonparser_.JsonParser createJsonParser2( + jni.JObject in0, + ) { + return const jsonparser_.$JsonParserType().fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_createJsonParser2, + jni.JniCallType.objectType, [in0.reference]).object); + } + + static final _id_createJsonParser3 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"createJsonParser", + r"(Ljava/io/Reader;)Lcom/fasterxml/jackson/core/JsonParser;"); + + /// from: public com.fasterxml.jackson.core.JsonParser createJsonParser(java.io.Reader r) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing parser for parsing + /// the contents accessed via specified Reader. + /// + /// The read stream will __not be owned__ by + /// the parser, it will still be managed (i.e. closed if + /// end-of-stream is reacher, or parser close method called) + /// if (and only if) com.fasterxml.jackson.core.JsonParser.Feature\#AUTO_CLOSE_SOURCE + /// is enabled. + ///@param r Reader to use for reading JSON content to parse + ///@return Parser constructed + ///@throws IOException if parser initialization fails due to I/O (read) problem + ///@throws JsonParseException if parser initialization fails due to content decoding problem + ///@deprecated Since 2.2, use \#createParser(Reader) instead. + jsonparser_.JsonParser createJsonParser3( + jni.JObject r, + ) { + return const jsonparser_.$JsonParserType().fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_createJsonParser3, + jni.JniCallType.objectType, [r.reference]).object); + } + + static final _id_createJsonParser4 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"createJsonParser", + r"([B)Lcom/fasterxml/jackson/core/JsonParser;"); + + /// from: public com.fasterxml.jackson.core.JsonParser createJsonParser(byte[] data) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing parser for parsing the contents of given byte array. + ///@param data Input content to parse + ///@return Parser constructed + ///@throws IOException if parser initialization fails due to I/O (read) problem + ///@throws JsonParseException if parser initialization fails due to content decoding problem + ///@deprecated Since 2.2, use \#createParser(byte[]) instead. + jsonparser_.JsonParser createJsonParser4( + jni.JArray data, + ) { + return const jsonparser_.$JsonParserType().fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_createJsonParser4, + jni.JniCallType.objectType, [data.reference]).object); + } + + static final _id_createJsonParser5 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"createJsonParser", + r"([BII)Lcom/fasterxml/jackson/core/JsonParser;"); + + /// from: public com.fasterxml.jackson.core.JsonParser createJsonParser(byte[] data, int offset, int len) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing parser for parsing + /// the contents of given byte array. + ///@param data Buffer that contains data to parse + ///@param offset Offset of the first data byte within buffer + ///@param len Length of contents to parse within buffer + ///@return Parser constructed + ///@throws IOException if parser initialization fails due to I/O (read) problem + ///@throws JsonParseException if parser initialization fails due to content decoding problem + ///@deprecated Since 2.2, use \#createParser(byte[],int,int) instead. + jsonparser_.JsonParser createJsonParser5( + jni.JArray data, + int offset, + int len, + ) { + return const jsonparser_.$JsonParserType().fromRef(jni.Jni.accessors + .callMethodWithArgs( + reference, _id_createJsonParser5, jni.JniCallType.objectType, [ + data.reference, + jni.JValueInt(offset), + jni.JValueInt(len) + ]).object); + } + + static final _id_createJsonParser6 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"createJsonParser", + r"(Ljava/lang/String;)Lcom/fasterxml/jackson/core/JsonParser;"); + + /// from: public com.fasterxml.jackson.core.JsonParser createJsonParser(java.lang.String content) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing parser for parsing + /// contents of given String. + ///@param content Input content to parse + ///@return Parser constructed + ///@throws IOException if parser initialization fails due to I/O (read) problem + ///@throws JsonParseException if parser initialization fails due to content decoding problem + ///@deprecated Since 2.2, use \#createParser(String) instead. + jsonparser_.JsonParser createJsonParser6( + jni.JString content, + ) { + return const jsonparser_.$JsonParserType().fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_createJsonParser6, + jni.JniCallType.objectType, [content.reference]).object); + } + + static final _id_createJsonGenerator = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"createJsonGenerator", + r"(Ljava/io/OutputStream;Lcom/fasterxml/jackson/core/JsonEncoding;)Lcom/fasterxml/jackson/core/JsonGenerator;"); + + /// from: public com.fasterxml.jackson.core.JsonGenerator createJsonGenerator(java.io.OutputStream out, com.fasterxml.jackson.core.JsonEncoding enc) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing JSON generator for writing JSON content + /// using specified output stream. + /// Encoding to use must be specified, and needs to be one of available + /// types (as per JSON specification). + /// + /// Underlying stream __is NOT owned__ by the generator constructed, + /// so that generator will NOT close the output stream when + /// JsonGenerator\#close is called (unless auto-closing + /// feature, + /// com.fasterxml.jackson.core.JsonGenerator.Feature\#AUTO_CLOSE_TARGET + /// is enabled). + /// Using application needs to close it explicitly if this is the case. + /// + /// Note: there are formats that use fixed encoding (like most binary data formats) + /// and that ignore passed in encoding. + ///@param out OutputStream to use for writing JSON content + ///@param enc Character encoding to use + ///@return Generator constructed + ///@throws IOException if parser initialization fails due to I/O (write) problem + ///@deprecated Since 2.2, use \#createGenerator(OutputStream, JsonEncoding) instead. + jni.JObject createJsonGenerator( + jni.JObject out, + jni.JObject enc, + ) { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_createJsonGenerator, + jni.JniCallType.objectType, + [out.reference, enc.reference]).object); + } + + static final _id_createJsonGenerator1 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"createJsonGenerator", + r"(Ljava/io/Writer;)Lcom/fasterxml/jackson/core/JsonGenerator;"); + + /// from: public com.fasterxml.jackson.core.JsonGenerator createJsonGenerator(java.io.Writer out) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for constructing JSON generator for writing JSON content + /// using specified Writer. + /// + /// Underlying stream __is NOT owned__ by the generator constructed, + /// so that generator will NOT close the Reader when + /// JsonGenerator\#close is called (unless auto-closing + /// feature, + /// com.fasterxml.jackson.core.JsonGenerator.Feature\#AUTO_CLOSE_TARGET is enabled). + /// Using application needs to close it explicitly. + ///@param out Writer to use for writing JSON content + ///@return Generator constructed + ///@throws IOException if parser initialization fails due to I/O (write) problem + ///@deprecated Since 2.2, use \#createGenerator(Writer) instead. + jni.JObject createJsonGenerator1( + jni.JObject out, + ) { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_createJsonGenerator1, + jni.JniCallType.objectType, + [out.reference]).object); + } + + static final _id_createJsonGenerator2 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"createJsonGenerator", + r"(Ljava/io/OutputStream;)Lcom/fasterxml/jackson/core/JsonGenerator;"); + + /// from: public com.fasterxml.jackson.core.JsonGenerator createJsonGenerator(java.io.OutputStream out) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Convenience method for constructing generator that uses default + /// encoding of the format (UTF-8 for JSON and most other data formats). + /// + /// Note: there are formats that use fixed encoding (like most binary data formats). + ///@param out OutputStream to use for writing JSON content + ///@return Generator constructed + ///@throws IOException if parser initialization fails due to I/O (write) problem + ///@deprecated Since 2.2, use \#createGenerator(OutputStream) instead. + jni.JObject createJsonGenerator2( + jni.JObject out, + ) { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_createJsonGenerator2, + jni.JniCallType.objectType, + [out.reference]).object); + } +} + +final class $JsonFactoryType extends jni.JObjType { + const $JsonFactoryType(); + + @override + String get signature => r"Lcom/fasterxml/jackson/core/JsonFactory;"; + + @override + JsonFactory fromRef(jni.JObjectPtr ref) => JsonFactory.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($JsonFactoryType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($JsonFactoryType) && other is $JsonFactoryType; + } +} + +/// from: com.fasterxml.jackson.core.JsonFactory$Feature +/// +/// Enumeration that defines all on/off features that can only be +/// changed for JsonFactory. +class JsonFactory_Feature extends jni.JObject { + @override + late final jni.JObjType $type = type; + + JsonFactory_Feature.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = + jni.Jni.findJClass(r"com/fasterxml/jackson/core/JsonFactory$Feature"); + + /// The type which includes information such as the signature of this class. + static const type = $JsonFactory_FeatureType(); + static final _id_values = jni.Jni.accessors.getStaticMethodIDOf( + _class.reference, + r"values", + r"()[Lcom/fasterxml/jackson/core/JsonFactory$Feature;"); + + /// from: static public com.fasterxml.jackson.core.JsonFactory.Feature[] values() + /// The returned object must be released after use, by calling the [release] method. + static jni.JArray values() { + return const jni.JArrayType($JsonFactory_FeatureType()).fromRef( + jni.Jni.accessors.callStaticMethodWithArgs(_class.reference, _id_values, + jni.JniCallType.objectType, []).object); + } + + static final _id_valueOf = jni.Jni.accessors.getStaticMethodIDOf( + _class.reference, + r"valueOf", + r"(Ljava/lang/String;)Lcom/fasterxml/jackson/core/JsonFactory$Feature;"); + + /// from: static public com.fasterxml.jackson.core.JsonFactory.Feature valueOf(java.lang.String name) + /// The returned object must be released after use, by calling the [release] method. + static JsonFactory_Feature valueOf( + jni.JString name, + ) { + return const $JsonFactory_FeatureType().fromRef(jni.Jni.accessors + .callStaticMethodWithArgs(_class.reference, _id_valueOf, + jni.JniCallType.objectType, [name.reference]).object); + } + + static final _id_collectDefaults = jni.Jni.accessors + .getStaticMethodIDOf(_class.reference, r"collectDefaults", r"()I"); + + /// from: static public int collectDefaults() + /// + /// Method that calculates bit set (flags) of all features that + /// are enabled by default. + ///@return Bit field of features enabled by default + static int collectDefaults() { + return jni.Jni.accessors.callStaticMethodWithArgs(_class.reference, + _id_collectDefaults, jni.JniCallType.intType, []).integer; + } + + static final _id_enabledByDefault = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"enabledByDefault", r"()Z"); + + /// from: public boolean enabledByDefault() + bool enabledByDefault() { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_enabledByDefault, + jni.JniCallType.booleanType, []).boolean; + } + + static final _id_enabledIn = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"enabledIn", r"(I)Z"); + + /// from: public boolean enabledIn(int flags) + bool enabledIn( + int flags, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_enabledIn, + jni.JniCallType.booleanType, [jni.JValueInt(flags)]).boolean; + } + + static final _id_getMask = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"getMask", r"()I"); + + /// from: public int getMask() + int getMask() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_getMask, jni.JniCallType.intType, []).integer; + } +} + +final class $JsonFactory_FeatureType extends jni.JObjType { + const $JsonFactory_FeatureType(); + + @override + String get signature => r"Lcom/fasterxml/jackson/core/JsonFactory$Feature;"; + + @override + JsonFactory_Feature fromRef(jni.JObjectPtr ref) => + JsonFactory_Feature.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($JsonFactory_FeatureType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($JsonFactory_FeatureType) && + other is $JsonFactory_FeatureType; + } +} diff --git a/pkgs/jnigen/test/jackson_core_test/third_party/dart_only/dart_bindings/com/fasterxml/jackson/core/JsonParser.dart b/pkgs/jnigen/test/jackson_core_test/third_party/dart_only/dart_bindings/com/fasterxml/jackson/core/JsonParser.dart new file mode 100644 index 000000000..d94c22059 --- /dev/null +++ b/pkgs/jnigen/test/jackson_core_test/third_party/dart_only/dart_bindings/com/fasterxml/jackson/core/JsonParser.dart @@ -0,0 +1,2700 @@ +// Generated from jackson-core which is licensed under the Apache License 2.0. +// The following copyright from the original authors applies. +// See https://github.com/FasterXML/jackson-core/blob/2.14/LICENSE +// +// Copyright (c) 2007 - The Jackson Project Authors +// Licensed under the Apache License, Version 2.0 (the "License") +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Autogenerated by jnigen. DO NOT EDIT! + +// ignore_for_file: annotate_overrides +// ignore_for_file: camel_case_extensions +// ignore_for_file: camel_case_types +// ignore_for_file: constant_identifier_names +// ignore_for_file: file_names +// ignore_for_file: lines_longer_than_80_chars +// ignore_for_file: no_leading_underscores_for_local_identifiers +// ignore_for_file: non_constant_identifier_names +// ignore_for_file: overridden_fields +// ignore_for_file: unnecessary_cast +// ignore_for_file: unused_element +// ignore_for_file: unused_field +// ignore_for_file: unused_import +// ignore_for_file: unused_local_variable +// ignore_for_file: unused_shown_name + +import "dart:isolate" show ReceivePort; +import "dart:ffi" as ffi; +import "package:jni/internal_helpers_for_jnigen.dart"; +import "package:jni/jni.dart" as jni; + +import "JsonToken.dart" as jsontoken_; + +/// from: com.fasterxml.jackson.core.JsonParser +/// +/// Base class that defines public API for reading JSON content. +/// Instances are created using factory methods of +/// a JsonFactory instance. +///@author Tatu Saloranta +class JsonParser extends jni.JObject { + @override + late final jni.JObjType $type = type; + + JsonParser.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = + jni.Jni.findJClass(r"com/fasterxml/jackson/core/JsonParser"); + + /// The type which includes information such as the signature of this class. + static const type = $JsonParserType(); + static final _id_DEFAULT_READ_CAPABILITIES = + jni.Jni.accessors.getStaticFieldIDOf( + _class.reference, + r"DEFAULT_READ_CAPABILITIES", + r"Lcom/fasterxml/jackson/core/util/JacksonFeatureSet;", + ); + + /// from: static protected final com.fasterxml.jackson.core.util.JacksonFeatureSet DEFAULT_READ_CAPABILITIES + /// The returned object must be released after use, by calling the [release] method. + /// + /// Default set of StreamReadCapabilityies that may be used as + /// basis for format-specific readers (or as bogus instance if non-null + /// set needs to be passed). + ///@since 2.12 + static jni.JObject get DEFAULT_READ_CAPABILITIES => + const jni.JObjectType().fromRef(jni.Jni.accessors + .getStaticField(_class.reference, _id_DEFAULT_READ_CAPABILITIES, + jni.JniCallType.objectType) + .object); + + static final _id_new0 = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"", r"()V"); + + /// from: protected void () + /// The returned object must be released after use, by calling the [release] method. + factory JsonParser() { + return JsonParser.fromRef(jni.Jni.accessors + .newObjectWithArgs(_class.reference, _id_new0, []).object); + } + + static final _id_new1 = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"", r"(I)V"); + + /// from: protected void (int features) + /// The returned object must be released after use, by calling the [release] method. + factory JsonParser.new1( + int features, + ) { + return JsonParser.fromRef(jni.Jni.accessors.newObjectWithArgs( + _class.reference, _id_new1, [jni.JValueInt(features)]).object); + } + + static final _id_getCodec = jni.Jni.accessors.getMethodIDOf(_class.reference, + r"getCodec", r"()Lcom/fasterxml/jackson/core/ObjectCodec;"); + + /// from: public abstract com.fasterxml.jackson.core.ObjectCodec getCodec() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Accessor for ObjectCodec associated with this + /// parser, if any. Codec is used by \#readValueAs(Class) + /// method (and its variants). + ///@return Codec assigned to this parser, if any; {@code null} if none + jni.JObject getCodec() { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, _id_getCodec, jni.JniCallType.objectType, []).object); + } + + static final _id_setCodec = jni.Jni.accessors.getMethodIDOf(_class.reference, + r"setCodec", r"(Lcom/fasterxml/jackson/core/ObjectCodec;)V"); + + /// from: public abstract void setCodec(com.fasterxml.jackson.core.ObjectCodec oc) + /// + /// Setter that allows defining ObjectCodec associated with this + /// parser, if any. Codec is used by \#readValueAs(Class) + /// method (and its variants). + ///@param oc Codec to assign, if any; {@code null} if none + void setCodec( + jni.JObject oc, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_setCodec, + jni.JniCallType.voidType, [oc.reference]).check(); + } + + static final _id_getInputSource = jni.Jni.accessors.getMethodIDOf( + _class.reference, r"getInputSource", r"()Ljava/lang/Object;"); + + /// from: public java.lang.Object getInputSource() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that can be used to get access to object that is used + /// to access input being parsed; this is usually either + /// InputStream or Reader, depending on what + /// parser was constructed with. + /// Note that returned value may be null in some cases; including + /// case where parser implementation does not want to exposed raw + /// source to caller. + /// In cases where input has been decorated, object returned here + /// is the decorated version; this allows some level of interaction + /// between users of parser and decorator object. + /// + /// In general use of this accessor should be considered as + /// "last effort", i.e. only used if no other mechanism is applicable. + ///@return Input source this parser was configured with + jni.JObject getInputSource() { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, _id_getInputSource, jni.JniCallType.objectType, []).object); + } + + static final _id_setRequestPayloadOnError = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"setRequestPayloadOnError", + r"(Lcom/fasterxml/jackson/core/util/RequestPayload;)V"); + + /// from: public void setRequestPayloadOnError(com.fasterxml.jackson.core.util.RequestPayload payload) + /// + /// Sets the payload to be passed if JsonParseException is thrown. + ///@param payload Payload to pass + ///@since 2.8 + void setRequestPayloadOnError( + jni.JObject payload, + ) { + return jni.Jni.accessors.callMethodWithArgs( + reference, + _id_setRequestPayloadOnError, + jni.JniCallType.voidType, + [payload.reference]).check(); + } + + static final _id_setRequestPayloadOnError1 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"setRequestPayloadOnError", + r"([BLjava/lang/String;)V"); + + /// from: public void setRequestPayloadOnError(byte[] payload, java.lang.String charset) + /// + /// Sets the byte[] request payload and the charset + ///@param payload Payload to pass + ///@param charset Character encoding for (lazily) decoding payload + ///@since 2.8 + void setRequestPayloadOnError1( + jni.JArray payload, + jni.JString charset, + ) { + return jni.Jni.accessors.callMethodWithArgs( + reference, + _id_setRequestPayloadOnError1, + jni.JniCallType.voidType, + [payload.reference, charset.reference]).check(); + } + + static final _id_setRequestPayloadOnError2 = jni.Jni.accessors.getMethodIDOf( + _class.reference, r"setRequestPayloadOnError", r"(Ljava/lang/String;)V"); + + /// from: public void setRequestPayloadOnError(java.lang.String payload) + /// + /// Sets the String request payload + ///@param payload Payload to pass + ///@since 2.8 + void setRequestPayloadOnError2( + jni.JString payload, + ) { + return jni.Jni.accessors.callMethodWithArgs( + reference, + _id_setRequestPayloadOnError2, + jni.JniCallType.voidType, + [payload.reference]).check(); + } + + static final _id_setSchema = jni.Jni.accessors.getMethodIDOf(_class.reference, + r"setSchema", r"(Lcom/fasterxml/jackson/core/FormatSchema;)V"); + + /// from: public void setSchema(com.fasterxml.jackson.core.FormatSchema schema) + /// + /// Method to call to make this parser use specified schema. Method must + /// be called before trying to parse any content, right after parser instance + /// has been created. + /// Note that not all parsers support schemas; and those that do usually only + /// accept specific types of schemas: ones defined for data format parser can read. + /// + /// If parser does not support specified schema, UnsupportedOperationException + /// is thrown. + ///@param schema Schema to use + ///@throws UnsupportedOperationException if parser does not support schema + void setSchema( + jni.JObject schema, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_setSchema, + jni.JniCallType.voidType, [schema.reference]).check(); + } + + static final _id_getSchema = jni.Jni.accessors.getMethodIDOf(_class.reference, + r"getSchema", r"()Lcom/fasterxml/jackson/core/FormatSchema;"); + + /// from: public com.fasterxml.jackson.core.FormatSchema getSchema() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for accessing Schema that this parser uses, if any. + /// Default implementation returns null. + ///@return Schema in use by this parser, if any; {@code null} if none + ///@since 2.1 + jni.JObject getSchema() { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, _id_getSchema, jni.JniCallType.objectType, []).object); + } + + static final _id_canUseSchema = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"canUseSchema", + r"(Lcom/fasterxml/jackson/core/FormatSchema;)Z"); + + /// from: public boolean canUseSchema(com.fasterxml.jackson.core.FormatSchema schema) + /// + /// Method that can be used to verify that given schema can be used with + /// this parser (using \#setSchema). + ///@param schema Schema to check + ///@return True if this parser can use given schema; false if not + bool canUseSchema( + jni.JObject schema, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_canUseSchema, + jni.JniCallType.booleanType, [schema.reference]).boolean; + } + + static final _id_requiresCustomCodec = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"requiresCustomCodec", r"()Z"); + + /// from: public boolean requiresCustomCodec() + /// + /// Method that can be called to determine if a custom + /// ObjectCodec is needed for binding data parsed + /// using JsonParser constructed by this factory + /// (which typically also implies the same for serialization + /// with JsonGenerator). + ///@return True if format-specific codec is needed with this parser; false if a general + /// ObjectCodec is enough + ///@since 2.1 + bool requiresCustomCodec() { + return jni.Jni.accessors.callMethodWithArgs(reference, + _id_requiresCustomCodec, jni.JniCallType.booleanType, []).boolean; + } + + static final _id_canParseAsync = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"canParseAsync", r"()Z"); + + /// from: public boolean canParseAsync() + /// + /// Method that can be called to determine if this parser instance + /// uses non-blocking ("asynchronous") input access for decoding or not. + /// Access mode is determined by earlier calls via JsonFactory; + /// it may not be changed after construction. + /// + /// If non-blocking decoding is (@code true}, it is possible to call + /// \#getNonBlockingInputFeeder() to obtain object to use + /// for feeding input; otherwise (false returned) + /// input is read by blocking + ///@return True if this is a non-blocking ("asynchronous") parser + ///@since 2.9 + bool canParseAsync() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_canParseAsync, jni.JniCallType.booleanType, []).boolean; + } + + static final _id_getNonBlockingInputFeeder = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"getNonBlockingInputFeeder", + r"()Lcom/fasterxml/jackson/core/async/NonBlockingInputFeeder;"); + + /// from: public com.fasterxml.jackson.core.async.NonBlockingInputFeeder getNonBlockingInputFeeder() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that will either return a feeder instance (if parser uses + /// non-blocking, aka asynchronous access); or null for + /// parsers that use blocking I/O. + ///@return Input feeder to use with non-blocking (async) parsing + ///@since 2.9 + jni.JObject getNonBlockingInputFeeder() { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_getNonBlockingInputFeeder, + jni.JniCallType.objectType, []).object); + } + + static final _id_getReadCapabilities = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"getReadCapabilities", + r"()Lcom/fasterxml/jackson/core/util/JacksonFeatureSet;"); + + /// from: public com.fasterxml.jackson.core.util.JacksonFeatureSet getReadCapabilities() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Accessor for getting metadata on capabilities of this parser, based on + /// underlying data format being read (directly or indirectly). + ///@return Set of read capabilities for content to read via this parser + ///@since 2.12 + jni.JObject getReadCapabilities() { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_getReadCapabilities, + jni.JniCallType.objectType, []).object); + } + + static final _id_version = jni.Jni.accessors.getMethodIDOf( + _class.reference, r"version", r"()Lcom/fasterxml/jackson/core/Version;"); + + /// from: public abstract com.fasterxml.jackson.core.Version version() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Accessor for getting version of the core package, given a parser instance. + /// Left for sub-classes to implement. + ///@return Version of this generator (derived from version declared for + /// {@code jackson-core} jar that contains the class + jni.JObject version() { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, _id_version, jni.JniCallType.objectType, []).object); + } + + static final _id_close = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"close", r"()V"); + + /// from: public abstract void close() + /// + /// Closes the parser so that no further iteration or data access + /// can be made; will also close the underlying input source + /// if parser either __owns__ the input source, or feature + /// Feature\#AUTO_CLOSE_SOURCE is enabled. + /// Whether parser owns the input source depends on factory + /// method that was used to construct instance (so check + /// com.fasterxml.jackson.core.JsonFactory for details, + /// but the general + /// idea is that if caller passes in closable resource (such + /// as InputStream or Reader) parser does NOT + /// own the source; but if it passes a reference (such as + /// java.io.File or java.net.URL and creates + /// stream or reader it does own them. + ///@throws IOException if there is either an underlying I/O problem + void close() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_close, jni.JniCallType.voidType, []).check(); + } + + static final _id_isClosed = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"isClosed", r"()Z"); + + /// from: public abstract boolean isClosed() + /// + /// Method that can be called to determine whether this parser + /// is closed or not. If it is closed, no new tokens can be + /// retrieved by calling \#nextToken (and the underlying + /// stream may be closed). Closing may be due to an explicit + /// call to \#close or because parser has encountered + /// end of input. + ///@return {@code True} if this parser instance has been closed + bool isClosed() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_isClosed, jni.JniCallType.booleanType, []).boolean; + } + + static final _id_getParsingContext = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"getParsingContext", + r"()Lcom/fasterxml/jackson/core/JsonStreamContext;"); + + /// from: public abstract com.fasterxml.jackson.core.JsonStreamContext getParsingContext() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that can be used to access current parsing context reader + /// is in. There are 3 different types: root, array and object contexts, + /// with slightly different available information. Contexts are + /// hierarchically nested, and can be used for example for figuring + /// out part of the input document that correspond to specific + /// array or object (for highlighting purposes, or error reporting). + /// Contexts can also be used for simple xpath-like matching of + /// input, if so desired. + ///@return Stream input context (JsonStreamContext) associated with this parser + jni.JObject getParsingContext() { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_getParsingContext, + jni.JniCallType.objectType, []).object); + } + + static final _id_currentLocation = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"currentLocation", + r"()Lcom/fasterxml/jackson/core/JsonLocation;"); + + /// from: public com.fasterxml.jackson.core.JsonLocation currentLocation() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that returns location of the last processed input unit (character + /// or byte) from the input; + /// usually for error reporting purposes. + /// + /// Note that the location is not guaranteed to be accurate (although most + /// implementation will try their best): some implementations may only + /// report specific boundary locations (start or end locations of tokens) + /// and others only return JsonLocation\#NA due to not having access + /// to input location information (when delegating actual decoding work + /// to other library) + ///@return Location of the last processed input unit (byte or character) + ///@since 2.13 + jni.JObject currentLocation() { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, _id_currentLocation, jni.JniCallType.objectType, []).object); + } + + static final _id_currentTokenLocation = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"currentTokenLocation", + r"()Lcom/fasterxml/jackson/core/JsonLocation;"); + + /// from: public com.fasterxml.jackson.core.JsonLocation currentTokenLocation() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that return the __starting__ location of the current + /// (most recently returned) + /// token; that is, the position of the first input unit (character or byte) from input + /// that starts the current token. + /// + /// Note that the location is not guaranteed to be accurate (although most + /// implementation will try their best): some implementations may only + /// return JsonLocation\#NA due to not having access + /// to input location information (when delegating actual decoding work + /// to other library) + ///@return Starting location of the token parser currently points to + ///@since 2.13 (will eventually replace \#getTokenLocation) + jni.JObject currentTokenLocation() { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_currentTokenLocation, + jni.JniCallType.objectType, []).object); + } + + static final _id_getCurrentLocation = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"getCurrentLocation", + r"()Lcom/fasterxml/jackson/core/JsonLocation;"); + + /// from: public abstract com.fasterxml.jackson.core.JsonLocation getCurrentLocation() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Alias for \#currentLocation(), to be deprecated in later + /// Jackson 2.x versions (and removed from Jackson 3.0). + ///@return Location of the last processed input unit (byte or character) + jni.JObject getCurrentLocation() { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_getCurrentLocation, + jni.JniCallType.objectType, []).object); + } + + static final _id_getTokenLocation = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"getTokenLocation", + r"()Lcom/fasterxml/jackson/core/JsonLocation;"); + + /// from: public abstract com.fasterxml.jackson.core.JsonLocation getTokenLocation() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Alias for \#currentTokenLocation(), to be deprecated in later + /// Jackson 2.x versions (and removed from Jackson 3.0). + ///@return Starting location of the token parser currently points to + jni.JObject getTokenLocation() { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_getTokenLocation, + jni.JniCallType.objectType, []).object); + } + + static final _id_currentValue = jni.Jni.accessors.getMethodIDOf( + _class.reference, r"currentValue", r"()Ljava/lang/Object;"); + + /// from: public java.lang.Object currentValue() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Helper method, usually equivalent to: + /// + /// getParsingContext().getCurrentValue(); + /// + /// + /// Note that "current value" is NOT populated (or used) by Streaming parser; + /// it is only used by higher-level data-binding functionality. + /// The reason it is included here is that it can be stored and accessed hierarchically, + /// and gets passed through data-binding. + ///@return "Current value" associated with the current input context (state) of this parser + ///@since 2.13 (added as replacement for older \#getCurrentValue() + jni.JObject currentValue() { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, _id_currentValue, jni.JniCallType.objectType, []).object); + } + + static final _id_assignCurrentValue = jni.Jni.accessors.getMethodIDOf( + _class.reference, r"assignCurrentValue", r"(Ljava/lang/Object;)V"); + + /// from: public void assignCurrentValue(java.lang.Object v) + /// + /// Helper method, usually equivalent to: + /// + /// getParsingContext().setCurrentValue(v); + /// + ///@param v Current value to assign for the current input context of this parser + ///@since 2.13 (added as replacement for older \#setCurrentValue + void assignCurrentValue( + jni.JObject v, + ) { + return jni.Jni.accessors.callMethodWithArgs( + reference, + _id_assignCurrentValue, + jni.JniCallType.voidType, + [v.reference]).check(); + } + + static final _id_getCurrentValue = jni.Jni.accessors.getMethodIDOf( + _class.reference, r"getCurrentValue", r"()Ljava/lang/Object;"); + + /// from: public java.lang.Object getCurrentValue() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Alias for \#currentValue(), to be deprecated in later + /// Jackson 2.x versions (and removed from Jackson 3.0). + ///@return Location of the last processed input unit (byte or character) + jni.JObject getCurrentValue() { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, _id_getCurrentValue, jni.JniCallType.objectType, []).object); + } + + static final _id_setCurrentValue = jni.Jni.accessors.getMethodIDOf( + _class.reference, r"setCurrentValue", r"(Ljava/lang/Object;)V"); + + /// from: public void setCurrentValue(java.lang.Object v) + /// + /// Alias for \#assignCurrentValue, to be deprecated in later + /// Jackson 2.x versions (and removed from Jackson 3.0). + ///@param v Current value to assign for the current input context of this parser + void setCurrentValue( + jni.JObject v, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_setCurrentValue, + jni.JniCallType.voidType, [v.reference]).check(); + } + + static final _id_releaseBuffered = jni.Jni.accessors.getMethodIDOf( + _class.reference, r"releaseBuffered", r"(Ljava/io/OutputStream;)I"); + + /// from: public int releaseBuffered(java.io.OutputStream out) + /// + /// Method that can be called to push back any content that + /// has been read but not consumed by the parser. This is usually + /// done after reading all content of interest using parser. + /// Content is released by writing it to given stream if possible; + /// if underlying input is byte-based it can released, if not (char-based) + /// it can not. + ///@param out OutputStream to which buffered, undecoded content is written to + ///@return -1 if the underlying content source is not byte based + /// (that is, input can not be sent to OutputStream; + /// otherwise number of bytes released (0 if there was nothing to release) + ///@throws IOException if write to stream threw exception + int releaseBuffered( + jni.JObject out, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_releaseBuffered, + jni.JniCallType.intType, [out.reference]).integer; + } + + static final _id_releaseBuffered1 = jni.Jni.accessors.getMethodIDOf( + _class.reference, r"releaseBuffered", r"(Ljava/io/Writer;)I"); + + /// from: public int releaseBuffered(java.io.Writer w) + /// + /// Method that can be called to push back any content that + /// has been read but not consumed by the parser. + /// This is usually + /// done after reading all content of interest using parser. + /// Content is released by writing it to given writer if possible; + /// if underlying input is char-based it can released, if not (byte-based) + /// it can not. + ///@param w Writer to which buffered but unprocessed content is written to + ///@return -1 if the underlying content source is not char-based + /// (that is, input can not be sent to Writer; + /// otherwise number of chars released (0 if there was nothing to release) + ///@throws IOException if write using Writer threw exception + int releaseBuffered1( + jni.JObject w, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_releaseBuffered1, + jni.JniCallType.intType, [w.reference]).integer; + } + + static final _id_enable = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"enable", + r"(Lcom/fasterxml/jackson/core/JsonParser$Feature;)Lcom/fasterxml/jackson/core/JsonParser;"); + + /// from: public com.fasterxml.jackson.core.JsonParser enable(com.fasterxml.jackson.core.JsonParser.Feature f) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for enabling specified parser feature + /// (check Feature for list of features) + ///@param f Feature to enable + ///@return This parser, to allow call chaining + JsonParser enable( + JsonParser_Feature f, + ) { + return const $JsonParserType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_enable, + jni.JniCallType.objectType, + [f.reference]).object); + } + + static final _id_disable = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"disable", + r"(Lcom/fasterxml/jackson/core/JsonParser$Feature;)Lcom/fasterxml/jackson/core/JsonParser;"); + + /// from: public com.fasterxml.jackson.core.JsonParser disable(com.fasterxml.jackson.core.JsonParser.Feature f) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for disabling specified feature + /// (check Feature for list of features) + ///@param f Feature to disable + ///@return This parser, to allow call chaining + JsonParser disable( + JsonParser_Feature f, + ) { + return const $JsonParserType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_disable, + jni.JniCallType.objectType, + [f.reference]).object); + } + + static final _id_configure = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"configure", + r"(Lcom/fasterxml/jackson/core/JsonParser$Feature;Z)Lcom/fasterxml/jackson/core/JsonParser;"); + + /// from: public com.fasterxml.jackson.core.JsonParser configure(com.fasterxml.jackson.core.JsonParser.Feature f, boolean state) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for enabling or disabling specified feature + /// (check Feature for list of features) + ///@param f Feature to enable or disable + ///@param state Whether to enable feature ({@code true}) or disable ({@code false}) + ///@return This parser, to allow call chaining + JsonParser configure( + JsonParser_Feature f, + bool state, + ) { + return const $JsonParserType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_configure, + jni.JniCallType.objectType, + [f.reference, state ? 1 : 0]).object); + } + + static final _id_isEnabled = jni.Jni.accessors.getMethodIDOf(_class.reference, + r"isEnabled", r"(Lcom/fasterxml/jackson/core/JsonParser$Feature;)Z"); + + /// from: public boolean isEnabled(com.fasterxml.jackson.core.JsonParser.Feature f) + /// + /// Method for checking whether specified Feature is enabled. + ///@param f Feature to check + ///@return {@code True} if feature is enabled; {@code false} otherwise + bool isEnabled( + JsonParser_Feature f, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_isEnabled, + jni.JniCallType.booleanType, [f.reference]).boolean; + } + + static final _id_isEnabled1 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"isEnabled", + r"(Lcom/fasterxml/jackson/core/StreamReadFeature;)Z"); + + /// from: public boolean isEnabled(com.fasterxml.jackson.core.StreamReadFeature f) + /// + /// Method for checking whether specified Feature is enabled. + ///@param f Feature to check + ///@return {@code True} if feature is enabled; {@code false} otherwise + ///@since 2.10 + bool isEnabled1( + jni.JObject f, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_isEnabled1, + jni.JniCallType.booleanType, [f.reference]).boolean; + } + + static final _id_getFeatureMask = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"getFeatureMask", r"()I"); + + /// from: public int getFeatureMask() + /// + /// Bulk access method for getting state of all standard Features. + ///@return Bit mask that defines current states of all standard Features. + ///@since 2.3 + int getFeatureMask() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_getFeatureMask, jni.JniCallType.intType, []).integer; + } + + static final _id_setFeatureMask = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"setFeatureMask", + r"(I)Lcom/fasterxml/jackson/core/JsonParser;"); + + /// from: public com.fasterxml.jackson.core.JsonParser setFeatureMask(int mask) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Bulk set method for (re)setting states of all standard Features + ///@param mask Bit mask that defines set of features to enable + ///@return This parser, to allow call chaining + ///@since 2.3 + ///@deprecated Since 2.7, use \#overrideStdFeatures(int, int) instead + JsonParser setFeatureMask( + int mask, + ) { + return const $JsonParserType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_setFeatureMask, + jni.JniCallType.objectType, + [jni.JValueInt(mask)]).object); + } + + static final _id_overrideStdFeatures = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"overrideStdFeatures", + r"(II)Lcom/fasterxml/jackson/core/JsonParser;"); + + /// from: public com.fasterxml.jackson.core.JsonParser overrideStdFeatures(int values, int mask) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Bulk set method for (re)setting states of features specified by mask. + /// Functionally equivalent to + /// + /// int oldState = getFeatureMask(); + /// int newState = (oldState & ~mask) | (values & mask); + /// setFeatureMask(newState); + /// + /// but preferred as this lets caller more efficiently specify actual changes made. + ///@param values Bit mask of set/clear state for features to change + ///@param mask Bit mask of features to change + ///@return This parser, to allow call chaining + ///@since 2.6 + JsonParser overrideStdFeatures( + int values, + int mask, + ) { + return const $JsonParserType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_overrideStdFeatures, + jni.JniCallType.objectType, + [jni.JValueInt(values), jni.JValueInt(mask)]).object); + } + + static final _id_getFormatFeatures = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"getFormatFeatures", r"()I"); + + /// from: public int getFormatFeatures() + /// + /// Bulk access method for getting state of all FormatFeatures, format-specific + /// on/off configuration settings. + ///@return Bit mask that defines current states of all standard FormatFeatures. + ///@since 2.6 + int getFormatFeatures() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_getFormatFeatures, jni.JniCallType.intType, []).integer; + } + + static final _id_overrideFormatFeatures = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"overrideFormatFeatures", + r"(II)Lcom/fasterxml/jackson/core/JsonParser;"); + + /// from: public com.fasterxml.jackson.core.JsonParser overrideFormatFeatures(int values, int mask) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Bulk set method for (re)setting states of FormatFeatures, + /// by specifying values (set / clear) along with a mask, to determine + /// which features to change, if any. + /// + /// Default implementation will simply throw an exception to indicate that + /// the parser implementation does not support any FormatFeatures. + ///@param values Bit mask of set/clear state for features to change + ///@param mask Bit mask of features to change + ///@return This parser, to allow call chaining + ///@since 2.6 + JsonParser overrideFormatFeatures( + int values, + int mask, + ) { + return const $JsonParserType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_overrideFormatFeatures, + jni.JniCallType.objectType, + [jni.JValueInt(values), jni.JValueInt(mask)]).object); + } + + static final _id_nextToken = jni.Jni.accessors.getMethodIDOf(_class.reference, + r"nextToken", r"()Lcom/fasterxml/jackson/core/JsonToken;"); + + /// from: public abstract com.fasterxml.jackson.core.JsonToken nextToken() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Main iteration method, which will advance stream enough + /// to determine type of the next token, if any. If none + /// remaining (stream has no content other than possible + /// white space before ending), null will be returned. + ///@return Next token from the stream, if any found, or null + /// to indicate end-of-input + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + jsontoken_.JsonToken nextToken() { + return const jsontoken_.$JsonTokenType().fromRef(jni.Jni.accessors + .callMethodWithArgs( + reference, _id_nextToken, jni.JniCallType.objectType, []).object); + } + + static final _id_nextValue = jni.Jni.accessors.getMethodIDOf(_class.reference, + r"nextValue", r"()Lcom/fasterxml/jackson/core/JsonToken;"); + + /// from: public abstract com.fasterxml.jackson.core.JsonToken nextValue() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Iteration method that will advance stream enough + /// to determine type of the next token that is a value type + /// (including JSON Array and Object start/end markers). + /// Or put another way, nextToken() will be called once, + /// and if JsonToken\#FIELD_NAME is returned, another + /// time to get the value for the field. + /// Method is most useful for iterating over value entries + /// of JSON objects; field name will still be available + /// by calling \#getCurrentName when parser points to + /// the value. + ///@return Next non-field-name token from the stream, if any found, + /// or null to indicate end-of-input (or, for non-blocking + /// parsers, JsonToken\#NOT_AVAILABLE if no tokens were + /// available yet) + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + jsontoken_.JsonToken nextValue() { + return const jsontoken_.$JsonTokenType().fromRef(jni.Jni.accessors + .callMethodWithArgs( + reference, _id_nextValue, jni.JniCallType.objectType, []).object); + } + + static final _id_nextFieldName = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"nextFieldName", + r"(Lcom/fasterxml/jackson/core/SerializableString;)Z"); + + /// from: public boolean nextFieldName(com.fasterxml.jackson.core.SerializableString str) + /// + /// Method that fetches next token (as if calling \#nextToken) and + /// verifies whether it is JsonToken\#FIELD_NAME with specified name + /// and returns result of that comparison. + /// It is functionally equivalent to: + ///
+  ///  return (nextToken() == JsonToken.FIELD_NAME) && str.getValue().equals(getCurrentName());
+  ///
+ /// but may be faster for parser to verify, and can therefore be used if caller + /// expects to get such a property name from input next. + ///@param str Property name to compare next token to (if next token is + /// JsonToken.FIELD_NAME) + ///@return {@code True} if parser advanced to {@code JsonToken.FIELD_NAME} with + /// specified name; {@code false} otherwise (different token or non-matching name) + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + bool nextFieldName( + jni.JObject str, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_nextFieldName, + jni.JniCallType.booleanType, [str.reference]).boolean; + } + + static final _id_nextFieldName1 = jni.Jni.accessors.getMethodIDOf( + _class.reference, r"nextFieldName", r"()Ljava/lang/String;"); + + /// from: public java.lang.String nextFieldName() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that fetches next token (as if calling \#nextToken) and + /// verifies whether it is JsonToken\#FIELD_NAME; if it is, + /// returns same as \#getCurrentName(), otherwise null. + ///@return Name of the the {@code JsonToken.FIELD_NAME} parser advanced to, if any; + /// {@code null} if next token is of some other type + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + ///@since 2.5 + jni.JString nextFieldName1() { + return const jni.JStringType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, _id_nextFieldName1, jni.JniCallType.objectType, []).object); + } + + static final _id_nextTextValue = jni.Jni.accessors.getMethodIDOf( + _class.reference, r"nextTextValue", r"()Ljava/lang/String;"); + + /// from: public java.lang.String nextTextValue() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that fetches next token (as if calling \#nextToken) and + /// if it is JsonToken\#VALUE_STRING returns contained String value; + /// otherwise returns null. + /// It is functionally equivalent to: + ///
+  ///  return (nextToken() == JsonToken.VALUE_STRING) ? getText() : null;
+  ///
+ /// but may be faster for parser to process, and can therefore be used if caller + /// expects to get a String value next from input. + ///@return Text value of the {@code JsonToken.VALUE_STRING} token parser advanced + /// to; or {@code null} if next token is of some other type + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + jni.JString nextTextValue() { + return const jni.JStringType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, _id_nextTextValue, jni.JniCallType.objectType, []).object); + } + + static final _id_nextIntValue = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"nextIntValue", r"(I)I"); + + /// from: public int nextIntValue(int defaultValue) + /// + /// Method that fetches next token (as if calling \#nextToken) and + /// if it is JsonToken\#VALUE_NUMBER_INT returns 32-bit int value; + /// otherwise returns specified default value + /// It is functionally equivalent to: + ///
+  ///  return (nextToken() == JsonToken.VALUE_NUMBER_INT) ? getIntValue() : defaultValue;
+  ///
+ /// but may be faster for parser to process, and can therefore be used if caller + /// expects to get an int value next from input. + /// + /// NOTE: value checks are performed similar to \#getIntValue() + ///@param defaultValue Value to return if next token is NOT of type {@code JsonToken.VALUE_NUMBER_INT} + ///@return Integer ({@code int}) value of the {@code JsonToken.VALUE_NUMBER_INT} token parser advanced + /// to; or {@code defaultValue} if next token is of some other type + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + ///@throws InputCoercionException if integer number does not fit in Java {@code int} + int nextIntValue( + int defaultValue, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_nextIntValue, + jni.JniCallType.intType, [jni.JValueInt(defaultValue)]).integer; + } + + static final _id_nextLongValue = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"nextLongValue", r"(J)J"); + + /// from: public long nextLongValue(long defaultValue) + /// + /// Method that fetches next token (as if calling \#nextToken) and + /// if it is JsonToken\#VALUE_NUMBER_INT returns 64-bit long value; + /// otherwise returns specified default value + /// It is functionally equivalent to: + ///
+  ///  return (nextToken() == JsonToken.VALUE_NUMBER_INT) ? getLongValue() : defaultValue;
+  ///
+ /// but may be faster for parser to process, and can therefore be used if caller + /// expects to get a long value next from input. + /// + /// NOTE: value checks are performed similar to \#getLongValue() + ///@param defaultValue Value to return if next token is NOT of type {@code JsonToken.VALUE_NUMBER_INT} + ///@return {@code long} value of the {@code JsonToken.VALUE_NUMBER_INT} token parser advanced + /// to; or {@code defaultValue} if next token is of some other type + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + ///@throws InputCoercionException if integer number does not fit in Java {@code long} + int nextLongValue( + int defaultValue, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_nextLongValue, + jni.JniCallType.longType, [defaultValue]).long; + } + + static final _id_nextBooleanValue = jni.Jni.accessors.getMethodIDOf( + _class.reference, r"nextBooleanValue", r"()Ljava/lang/Boolean;"); + + /// from: public java.lang.Boolean nextBooleanValue() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that fetches next token (as if calling \#nextToken) and + /// if it is JsonToken\#VALUE_TRUE or JsonToken\#VALUE_FALSE + /// returns matching Boolean value; otherwise return null. + /// It is functionally equivalent to: + ///
+  ///  JsonToken t = nextToken();
+  ///  if (t == JsonToken.VALUE_TRUE) return Boolean.TRUE;
+  ///  if (t == JsonToken.VALUE_FALSE) return Boolean.FALSE;
+  ///  return null;
+  ///
+ /// but may be faster for parser to process, and can therefore be used if caller + /// expects to get a Boolean value next from input. + ///@return {@code Boolean} value of the {@code JsonToken.VALUE_TRUE} or {@code JsonToken.VALUE_FALSE} + /// token parser advanced to; or {@code null} if next token is of some other type + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + jni.JBoolean nextBooleanValue() { + return const jni.JBooleanType().fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_nextBooleanValue, + jni.JniCallType.objectType, []).object); + } + + static final _id_skipChildren = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"skipChildren", + r"()Lcom/fasterxml/jackson/core/JsonParser;"); + + /// from: public abstract com.fasterxml.jackson.core.JsonParser skipChildren() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that will skip all child tokens of an array or + /// object token that the parser currently points to, + /// iff stream points to + /// JsonToken\#START_OBJECT or JsonToken\#START_ARRAY. + /// If not, it will do nothing. + /// After skipping, stream will point to __matching__ + /// JsonToken\#END_OBJECT or JsonToken\#END_ARRAY + /// (possibly skipping nested pairs of START/END OBJECT/ARRAY tokens + /// as well as value tokens). + /// The idea is that after calling this method, application + /// will call \#nextToken to point to the next + /// available token, if any. + ///@return This parser, to allow call chaining + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + JsonParser skipChildren() { + return const $JsonParserType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, _id_skipChildren, jni.JniCallType.objectType, []).object); + } + + static final _id_finishToken = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"finishToken", r"()V"); + + /// from: public void finishToken() + /// + /// Method that may be used to force full handling of the current token + /// so that even if lazy processing is enabled, the whole contents are + /// read for possible retrieval. This is usually used to ensure that + /// the token end location is available, as well as token contents + /// (similar to what calling, say \#getTextCharacters(), would + /// achieve). + /// + /// Note that for many dataformat implementations this method + /// will not do anything; this is the default implementation unless + /// overridden by sub-classes. + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + ///@since 2.8 + void finishToken() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_finishToken, jni.JniCallType.voidType, []).check(); + } + + static final _id_currentToken = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"currentToken", + r"()Lcom/fasterxml/jackson/core/JsonToken;"); + + /// from: public com.fasterxml.jackson.core.JsonToken currentToken() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Accessor to find which token parser currently points to, if any; + /// null will be returned if none. + /// If return value is non-null, data associated with the token + /// is available via other accessor methods. + ///@return Type of the token this parser currently points to, + /// if any: null before any tokens have been read, and + /// after end-of-input has been encountered, as well as + /// if the current token has been explicitly cleared. + ///@since 2.8 + jsontoken_.JsonToken currentToken() { + return const jsontoken_.$JsonTokenType().fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_currentToken, + jni.JniCallType.objectType, []).object); + } + + static final _id_currentTokenId = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"currentTokenId", r"()I"); + + /// from: public int currentTokenId() + /// + /// Method similar to \#getCurrentToken() but that returns an + /// int instead of JsonToken (enum value). + /// + /// Use of int directly is typically more efficient on switch statements, + /// so this method may be useful when building low-overhead codecs. + /// Note, however, that effect may not be big enough to matter: make sure + /// to profile performance before deciding to use this method. + ///@since 2.8 + ///@return {@code int} matching one of constants from JsonTokenId. + int currentTokenId() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_currentTokenId, jni.JniCallType.intType, []).integer; + } + + static final _id_getCurrentToken = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"getCurrentToken", + r"()Lcom/fasterxml/jackson/core/JsonToken;"); + + /// from: public abstract com.fasterxml.jackson.core.JsonToken getCurrentToken() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Alias for \#currentToken(), may be deprecated sometime after + /// Jackson 2.13 (will be removed from 3.0). + ///@return Type of the token this parser currently points to, + /// if any: null before any tokens have been read, and + jsontoken_.JsonToken getCurrentToken() { + return const jsontoken_.$JsonTokenType().fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_getCurrentToken, + jni.JniCallType.objectType, []).object); + } + + static final _id_getCurrentTokenId = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"getCurrentTokenId", r"()I"); + + /// from: public abstract int getCurrentTokenId() + /// + /// Deprecated alias for \#currentTokenId(). + ///@return {@code int} matching one of constants from JsonTokenId. + ///@deprecated Since 2.12 use \#currentTokenId instead + int getCurrentTokenId() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_getCurrentTokenId, jni.JniCallType.intType, []).integer; + } + + static final _id_hasCurrentToken = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"hasCurrentToken", r"()Z"); + + /// from: public abstract boolean hasCurrentToken() + /// + /// Method for checking whether parser currently points to + /// a token (and data for that token is available). + /// Equivalent to check for parser.getCurrentToken() != null. + ///@return True if the parser just returned a valid + /// token via \#nextToken; false otherwise (parser + /// was just constructed, encountered end-of-input + /// and returned null from \#nextToken, or the token + /// has been consumed) + bool hasCurrentToken() { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_hasCurrentToken, + jni.JniCallType.booleanType, []).boolean; + } + + static final _id_hasTokenId = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"hasTokenId", r"(I)Z"); + + /// from: public abstract boolean hasTokenId(int id) + /// + /// Method that is functionally equivalent to: + /// + /// return currentTokenId() == id + /// + /// but may be more efficiently implemented. + /// + /// Note that no traversal or conversion is performed; so in some + /// cases calling method like \#isExpectedStartArrayToken() + /// is necessary instead. + ///@param id Token id to match (from (@link JsonTokenId}) + ///@return {@code True} if the parser current points to specified token + ///@since 2.5 + bool hasTokenId( + int id, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_hasTokenId, + jni.JniCallType.booleanType, [jni.JValueInt(id)]).boolean; + } + + static final _id_hasToken = jni.Jni.accessors.getMethodIDOf(_class.reference, + r"hasToken", r"(Lcom/fasterxml/jackson/core/JsonToken;)Z"); + + /// from: public abstract boolean hasToken(com.fasterxml.jackson.core.JsonToken t) + /// + /// Method that is functionally equivalent to: + /// + /// return currentToken() == t + /// + /// but may be more efficiently implemented. + /// + /// Note that no traversal or conversion is performed; so in some + /// cases calling method like \#isExpectedStartArrayToken() + /// is necessary instead. + ///@param t Token to match + ///@return {@code True} if the parser current points to specified token + ///@since 2.6 + bool hasToken( + jsontoken_.JsonToken t, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_hasToken, + jni.JniCallType.booleanType, [t.reference]).boolean; + } + + static final _id_isExpectedStartArrayToken = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"isExpectedStartArrayToken", r"()Z"); + + /// from: public boolean isExpectedStartArrayToken() + /// + /// Specialized accessor that can be used to verify that the current + /// token indicates start array (usually meaning that current token + /// is JsonToken\#START_ARRAY) when start array is expected. + /// For some specialized parsers this can return true for other cases + /// as well; this is usually done to emulate arrays in cases underlying + /// format is ambiguous (XML, for example, has no format-level difference + /// between Objects and Arrays; it just has elements). + /// + /// Default implementation is equivalent to: + ///
+  ///   currentToken() == JsonToken.START_ARRAY
+  ///
+ /// but may be overridden by custom parser implementations. + ///@return True if the current token can be considered as a + /// start-array marker (such JsonToken\#START_ARRAY); + /// {@code false} if not + bool isExpectedStartArrayToken() { + return jni.Jni.accessors.callMethodWithArgs(reference, + _id_isExpectedStartArrayToken, jni.JniCallType.booleanType, []).boolean; + } + + static final _id_isExpectedStartObjectToken = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"isExpectedStartObjectToken", r"()Z"); + + /// from: public boolean isExpectedStartObjectToken() + /// + /// Similar to \#isExpectedStartArrayToken(), but checks whether stream + /// currently points to JsonToken\#START_OBJECT. + ///@return True if the current token can be considered as a + /// start-array marker (such JsonToken\#START_OBJECT); + /// {@code false} if not + ///@since 2.5 + bool isExpectedStartObjectToken() { + return jni.Jni.accessors.callMethodWithArgs( + reference, + _id_isExpectedStartObjectToken, + jni.JniCallType.booleanType, []).boolean; + } + + static final _id_isExpectedNumberIntToken = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"isExpectedNumberIntToken", r"()Z"); + + /// from: public boolean isExpectedNumberIntToken() + /// + /// Similar to \#isExpectedStartArrayToken(), but checks whether stream + /// currently points to JsonToken\#VALUE_NUMBER_INT. + /// + /// The initial use case is for XML backend to efficiently (attempt to) coerce + /// textual content into numbers. + ///@return True if the current token can be considered as a + /// start-array marker (such JsonToken\#VALUE_NUMBER_INT); + /// {@code false} if not + ///@since 2.12 + bool isExpectedNumberIntToken() { + return jni.Jni.accessors.callMethodWithArgs(reference, + _id_isExpectedNumberIntToken, jni.JniCallType.booleanType, []).boolean; + } + + static final _id_isNaN = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"isNaN", r"()Z"); + + /// from: public boolean isNaN() + /// + /// Access for checking whether current token is a numeric value token, but + /// one that is of "not-a-number" (NaN) variety (including both "NaN" AND + /// positive/negative infinity!): not supported by all formats, + /// but often supported for JsonToken\#VALUE_NUMBER_FLOAT. + /// NOTE: roughly equivalent to calling !Double.isFinite() + /// on value you would get from calling \#getDoubleValue(). + ///@return {@code True} if the current token is of type JsonToken\#VALUE_NUMBER_FLOAT + /// but represents a "Not a Number"; {@code false} for other tokens and regular + /// floating-point numbers + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + ///@since 2.9 + bool isNaN() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_isNaN, jni.JniCallType.booleanType, []).boolean; + } + + static final _id_clearCurrentToken = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"clearCurrentToken", r"()V"); + + /// from: public abstract void clearCurrentToken() + /// + /// Method called to "consume" the current token by effectively + /// removing it so that \#hasCurrentToken returns false, and + /// \#getCurrentToken null). + /// Cleared token value can still be accessed by calling + /// \#getLastClearedToken (if absolutely needed), but + /// usually isn't. + /// + /// Method was added to be used by the optional data binder, since + /// it has to be able to consume last token used for binding (so that + /// it will not be used again). + void clearCurrentToken() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_clearCurrentToken, jni.JniCallType.voidType, []).check(); + } + + static final _id_getLastClearedToken = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"getLastClearedToken", + r"()Lcom/fasterxml/jackson/core/JsonToken;"); + + /// from: public abstract com.fasterxml.jackson.core.JsonToken getLastClearedToken() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that can be called to get the last token that was + /// cleared using \#clearCurrentToken. This is not necessarily + /// the latest token read. + /// Will return null if no tokens have been cleared, + /// or if parser has been closed. + ///@return Last cleared token, if any; {@code null} otherwise + jsontoken_.JsonToken getLastClearedToken() { + return const jsontoken_.$JsonTokenType().fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_getLastClearedToken, + jni.JniCallType.objectType, []).object); + } + + static final _id_overrideCurrentName = jni.Jni.accessors.getMethodIDOf( + _class.reference, r"overrideCurrentName", r"(Ljava/lang/String;)V"); + + /// from: public abstract void overrideCurrentName(java.lang.String name) + /// + /// Method that can be used to change what is considered to be + /// the current (field) name. + /// May be needed to support non-JSON data formats or unusual binding + /// conventions; not needed for typical processing. + /// + /// Note that use of this method should only be done as sort of last + /// resort, as it is a work-around for regular operation. + ///@param name Name to use as the current name; may be null. + void overrideCurrentName( + jni.JString name, + ) { + return jni.Jni.accessors.callMethodWithArgs( + reference, + _id_overrideCurrentName, + jni.JniCallType.voidType, + [name.reference]).check(); + } + + static final _id_getCurrentName = jni.Jni.accessors.getMethodIDOf( + _class.reference, r"getCurrentName", r"()Ljava/lang/String;"); + + /// from: public abstract java.lang.String getCurrentName() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Alias of \#currentName(). + ///@return Name of the current field in the parsing context + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + jni.JString getCurrentName() { + return const jni.JStringType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, _id_getCurrentName, jni.JniCallType.objectType, []).object); + } + + static final _id_currentName = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"currentName", r"()Ljava/lang/String;"); + + /// from: public java.lang.String currentName() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that can be called to get the name associated with + /// the current token: for JsonToken\#FIELD_NAMEs it will + /// be the same as what \#getText returns; + /// for field values it will be preceding field name; + /// and for others (array values, root-level values) null. + ///@return Name of the current field in the parsing context + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + ///@since 2.10 + jni.JString currentName() { + return const jni.JStringType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, _id_currentName, jni.JniCallType.objectType, []).object); + } + + static final _id_getText = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"getText", r"()Ljava/lang/String;"); + + /// from: public abstract java.lang.String getText() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for accessing textual representation of the current token; + /// if no current token (before first call to \#nextToken, or + /// after encountering end-of-input), returns null. + /// Method can be called for any token type. + ///@return Textual value associated with the current token (one returned + /// by \#nextToken() or other iteration methods) + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + jni.JString getText() { + return const jni.JStringType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, _id_getText, jni.JniCallType.objectType, []).object); + } + + static final _id_getText1 = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"getText", r"(Ljava/io/Writer;)I"); + + /// from: public int getText(java.io.Writer writer) + /// + /// Method to read the textual representation of the current token in chunks and + /// pass it to the given Writer. + /// Conceptually same as calling: + ///
+  ///  writer.write(parser.getText());
+  ///
+ /// but should typically be more efficient as longer content does need to + /// be combined into a single String to return, and write + /// can occur directly from intermediate buffers Jackson uses. + ///@param writer Writer to write textual content to + ///@return The number of characters written to the Writer + ///@throws IOException for low-level read issues or writes using passed + /// {@code writer}, or + /// JsonParseException for decoding problems + ///@since 2.8 + int getText1( + jni.JObject writer, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_getText1, + jni.JniCallType.intType, [writer.reference]).integer; + } + + static final _id_getTextCharacters = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"getTextCharacters", r"()[C"); + + /// from: public abstract char[] getTextCharacters() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method similar to \#getText, but that will return + /// underlying (unmodifiable) character array that contains + /// textual value, instead of constructing a String object + /// to contain this information. + /// Note, however, that: + ///
    + ///
  • Textual contents are not guaranteed to start at + /// index 0 (rather, call \#getTextOffset) to + /// know the actual offset + ///
  • + ///
  • Length of textual contents may be less than the + /// length of returned buffer: call \#getTextLength + /// for actual length of returned content. + ///
  • + ///
+ /// + /// Note that caller __MUST NOT__ modify the returned + /// character array in any way -- doing so may corrupt + /// current parser state and render parser instance useless. + /// + /// The only reason to call this method (over \#getText) + /// is to avoid construction of a String object (which + /// will make a copy of contents). + ///@return Buffer that contains the current textual value (but not necessarily + /// at offset 0, and not necessarily until the end of buffer) + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + jni.JArray getTextCharacters() { + return const jni.JArrayType(jni.jcharType()).fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_getTextCharacters, + jni.JniCallType.objectType, []).object); + } + + static final _id_getTextLength = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"getTextLength", r"()I"); + + /// from: public abstract int getTextLength() + /// + /// Accessor used with \#getTextCharacters, to know length + /// of String stored in returned buffer. + ///@return Number of characters within buffer returned + /// by \#getTextCharacters that are part of + /// textual content of the current token. + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + int getTextLength() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_getTextLength, jni.JniCallType.intType, []).integer; + } + + static final _id_getTextOffset = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"getTextOffset", r"()I"); + + /// from: public abstract int getTextOffset() + /// + /// Accessor used with \#getTextCharacters, to know offset + /// of the first text content character within buffer. + ///@return Offset of the first character within buffer returned + /// by \#getTextCharacters that is part of + /// textual content of the current token. + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + int getTextOffset() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_getTextOffset, jni.JniCallType.intType, []).integer; + } + + static final _id_hasTextCharacters = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"hasTextCharacters", r"()Z"); + + /// from: public abstract boolean hasTextCharacters() + /// + /// Method that can be used to determine whether calling of + /// \#getTextCharacters would be the most efficient + /// way to access textual content for the event parser currently + /// points to. + /// + /// Default implementation simply returns false since only actual + /// implementation class has knowledge of its internal buffering + /// state. + /// Implementations are strongly encouraged to properly override + /// this method, to allow efficient copying of content by other + /// code. + ///@return True if parser currently has character array that can + /// be efficiently returned via \#getTextCharacters; false + /// means that it may or may not exist + bool hasTextCharacters() { + return jni.Jni.accessors.callMethodWithArgs(reference, + _id_hasTextCharacters, jni.JniCallType.booleanType, []).boolean; + } + + static final _id_getNumberValue = jni.Jni.accessors.getMethodIDOf( + _class.reference, r"getNumberValue", r"()Ljava/lang/Number;"); + + /// from: public abstract java.lang.Number getNumberValue() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Generic number value accessor method that will work for + /// all kinds of numeric values. It will return the optimal + /// (simplest/smallest possible) wrapper object that can + /// express the numeric value just parsed. + ///@return Numeric value of the current token in its most optimal + /// representation + ///@throws IOException Problem with access: JsonParseException if + /// the current token is not numeric, or if decoding of the value fails + /// (invalid format for numbers); plain IOException if underlying + /// content read fails (possible if values are extracted lazily) + jni.JNumber getNumberValue() { + return const jni.JNumberType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, _id_getNumberValue, jni.JniCallType.objectType, []).object); + } + + static final _id_getNumberValueExact = jni.Jni.accessors.getMethodIDOf( + _class.reference, r"getNumberValueExact", r"()Ljava/lang/Number;"); + + /// from: public java.lang.Number getNumberValueExact() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method similar to \#getNumberValue with the difference that + /// for floating-point numbers value returned may be BigDecimal + /// if the underlying format does not store floating-point numbers using + /// native representation: for example, textual formats represent numbers + /// as Strings (which are 10-based), and conversion to java.lang.Double + /// is potentially lossy operation. + /// + /// Default implementation simply returns \#getNumberValue() + ///@return Numeric value of the current token using most accurate representation + ///@throws IOException Problem with access: JsonParseException if + /// the current token is not numeric, or if decoding of the value fails + /// (invalid format for numbers); plain IOException if underlying + /// content read fails (possible if values are extracted lazily) + ///@since 2.12 + jni.JNumber getNumberValueExact() { + return const jni.JNumberType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_getNumberValueExact, + jni.JniCallType.objectType, []).object); + } + + static final _id_getNumberType = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"getNumberType", + r"()Lcom/fasterxml/jackson/core/JsonParser$NumberType;"); + + /// from: public abstract com.fasterxml.jackson.core.JsonParser.NumberType getNumberType() + /// The returned object must be released after use, by calling the [release] method. + /// + /// If current token is of type + /// JsonToken\#VALUE_NUMBER_INT or + /// JsonToken\#VALUE_NUMBER_FLOAT, returns + /// one of NumberType constants; otherwise returns null. + ///@return Type of current number, if parser points to numeric token; {@code null} otherwise + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + JsonParser_NumberType getNumberType() { + return const $JsonParser_NumberTypeType().fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_getNumberType, + jni.JniCallType.objectType, []).object); + } + + static final _id_getByteValue = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"getByteValue", r"()B"); + + /// from: public byte getByteValue() + /// + /// Numeric accessor that can be called when the current + /// token is of type JsonToken\#VALUE_NUMBER_INT and + /// it can be expressed as a value of Java byte primitive type. + /// Note that in addition to "natural" input range of {@code [-128, 127]}, + /// this also allows "unsigned 8-bit byte" values {@code [128, 255]}: + /// but for this range value will be translated by truncation, leading + /// to sign change. + /// + /// It can also be called for JsonToken\#VALUE_NUMBER_FLOAT; + /// if so, it is equivalent to calling \#getDoubleValue + /// and then casting; except for possible overflow/underflow + /// exception. + /// + /// Note: if the resulting integer value falls outside range of + /// {@code [-128, 255]}, + /// a InputCoercionException + /// will be thrown to indicate numeric overflow/underflow. + ///@return Current number value as {@code byte} (if numeric token within + /// range of {@code [-128, 255]}); otherwise exception thrown + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + int getByteValue() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_getByteValue, jni.JniCallType.byteType, []).byte; + } + + static final _id_getShortValue = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"getShortValue", r"()S"); + + /// from: public short getShortValue() + /// + /// Numeric accessor that can be called when the current + /// token is of type JsonToken\#VALUE_NUMBER_INT and + /// it can be expressed as a value of Java short primitive type. + /// It can also be called for JsonToken\#VALUE_NUMBER_FLOAT; + /// if so, it is equivalent to calling \#getDoubleValue + /// and then casting; except for possible overflow/underflow + /// exception. + /// + /// Note: if the resulting integer value falls outside range of + /// Java short, a InputCoercionException + /// will be thrown to indicate numeric overflow/underflow. + ///@return Current number value as {@code short} (if numeric token within + /// Java 16-bit signed {@code short} range); otherwise exception thrown + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + int getShortValue() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_getShortValue, jni.JniCallType.shortType, []).short; + } + + static final _id_getIntValue = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"getIntValue", r"()I"); + + /// from: public abstract int getIntValue() + /// + /// Numeric accessor that can be called when the current + /// token is of type JsonToken\#VALUE_NUMBER_INT and + /// it can be expressed as a value of Java int primitive type. + /// It can also be called for JsonToken\#VALUE_NUMBER_FLOAT; + /// if so, it is equivalent to calling \#getDoubleValue + /// and then casting; except for possible overflow/underflow + /// exception. + /// + /// Note: if the resulting integer value falls outside range of + /// Java {@code int}, a InputCoercionException + /// may be thrown to indicate numeric overflow/underflow. + ///@return Current number value as {@code int} (if numeric token within + /// Java 32-bit signed {@code int} range); otherwise exception thrown + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + int getIntValue() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_getIntValue, jni.JniCallType.intType, []).integer; + } + + static final _id_getLongValue = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"getLongValue", r"()J"); + + /// from: public abstract long getLongValue() + /// + /// Numeric accessor that can be called when the current + /// token is of type JsonToken\#VALUE_NUMBER_INT and + /// it can be expressed as a Java long primitive type. + /// It can also be called for JsonToken\#VALUE_NUMBER_FLOAT; + /// if so, it is equivalent to calling \#getDoubleValue + /// and then casting to int; except for possible overflow/underflow + /// exception. + /// + /// Note: if the token is an integer, but its value falls + /// outside of range of Java long, a InputCoercionException + /// may be thrown to indicate numeric overflow/underflow. + ///@return Current number value as {@code long} (if numeric token within + /// Java 32-bit signed {@code long} range); otherwise exception thrown + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + int getLongValue() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_getLongValue, jni.JniCallType.longType, []).long; + } + + static final _id_getBigIntegerValue = jni.Jni.accessors.getMethodIDOf( + _class.reference, r"getBigIntegerValue", r"()Ljava/math/BigInteger;"); + + /// from: public abstract java.math.BigInteger getBigIntegerValue() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Numeric accessor that can be called when the current + /// token is of type JsonToken\#VALUE_NUMBER_INT and + /// it can not be used as a Java long primitive type due to its + /// magnitude. + /// It can also be called for JsonToken\#VALUE_NUMBER_FLOAT; + /// if so, it is equivalent to calling \#getDecimalValue + /// and then constructing a BigInteger from that value. + ///@return Current number value as BigInteger (if numeric token); + /// otherwise exception thrown + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + jni.JObject getBigIntegerValue() { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_getBigIntegerValue, + jni.JniCallType.objectType, []).object); + } + + static final _id_getFloatValue = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"getFloatValue", r"()F"); + + /// from: public abstract float getFloatValue() + /// + /// Numeric accessor that can be called when the current + /// token is of type JsonToken\#VALUE_NUMBER_FLOAT and + /// it can be expressed as a Java float primitive type. + /// It can also be called for JsonToken\#VALUE_NUMBER_INT; + /// if so, it is equivalent to calling \#getLongValue + /// and then casting; except for possible overflow/underflow + /// exception. + /// + /// Note: if the value falls + /// outside of range of Java float, a InputCoercionException + /// will be thrown to indicate numeric overflow/underflow. + ///@return Current number value as {@code float} (if numeric token within + /// Java {@code float} range); otherwise exception thrown + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + double getFloatValue() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_getFloatValue, jni.JniCallType.floatType, []).float; + } + + static final _id_getDoubleValue = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"getDoubleValue", r"()D"); + + /// from: public abstract double getDoubleValue() + /// + /// Numeric accessor that can be called when the current + /// token is of type JsonToken\#VALUE_NUMBER_FLOAT and + /// it can be expressed as a Java double primitive type. + /// It can also be called for JsonToken\#VALUE_NUMBER_INT; + /// if so, it is equivalent to calling \#getLongValue + /// and then casting; except for possible overflow/underflow + /// exception. + /// + /// Note: if the value falls + /// outside of range of Java double, a InputCoercionException + /// will be thrown to indicate numeric overflow/underflow. + ///@return Current number value as {@code double} (if numeric token within + /// Java {@code double} range); otherwise exception thrown + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + double getDoubleValue() { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_getDoubleValue, + jni.JniCallType.doubleType, []).doubleFloat; + } + + static final _id_getDecimalValue = jni.Jni.accessors.getMethodIDOf( + _class.reference, r"getDecimalValue", r"()Ljava/math/BigDecimal;"); + + /// from: public abstract java.math.BigDecimal getDecimalValue() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Numeric accessor that can be called when the current + /// token is of type JsonToken\#VALUE_NUMBER_FLOAT or + /// JsonToken\#VALUE_NUMBER_INT. No under/overflow exceptions + /// are ever thrown. + ///@return Current number value as BigDecimal (if numeric token); + /// otherwise exception thrown + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + jni.JObject getDecimalValue() { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, _id_getDecimalValue, jni.JniCallType.objectType, []).object); + } + + static final _id_getBooleanValue = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"getBooleanValue", r"()Z"); + + /// from: public boolean getBooleanValue() + /// + /// Convenience accessor that can be called when the current + /// token is JsonToken\#VALUE_TRUE or + /// JsonToken\#VALUE_FALSE, to return matching {@code boolean} + /// value. + /// If the current token is of some other type, JsonParseException + /// will be thrown + ///@return {@code True} if current token is {@code JsonToken.VALUE_TRUE}, + /// {@code false} if current token is {@code JsonToken.VALUE_FALSE}; + /// otherwise throws JsonParseException + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + bool getBooleanValue() { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_getBooleanValue, + jni.JniCallType.booleanType, []).boolean; + } + + static final _id_getEmbeddedObject = jni.Jni.accessors.getMethodIDOf( + _class.reference, r"getEmbeddedObject", r"()Ljava/lang/Object;"); + + /// from: public java.lang.Object getEmbeddedObject() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Accessor that can be called if (and only if) the current token + /// is JsonToken\#VALUE_EMBEDDED_OBJECT. For other token types, + /// null is returned. + /// + /// Note: only some specialized parser implementations support + /// embedding of objects (usually ones that are facades on top + /// of non-streaming sources, such as object trees). One exception + /// is access to binary content (whether via base64 encoding or not) + /// which typically is accessible using this method, as well as + /// \#getBinaryValue(). + ///@return Embedded value (usually of "native" type supported by format) + /// for the current token, if any; {@code null otherwise} + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + jni.JObject getEmbeddedObject() { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_getEmbeddedObject, + jni.JniCallType.objectType, []).object); + } + + static final _id_getBinaryValue = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"getBinaryValue", + r"(Lcom/fasterxml/jackson/core/Base64Variant;)[B"); + + /// from: public abstract byte[] getBinaryValue(com.fasterxml.jackson.core.Base64Variant bv) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that can be used to read (and consume -- results + /// may not be accessible using other methods after the call) + /// base64-encoded binary data + /// included in the current textual JSON value. + /// It works similar to getting String value via \#getText + /// and decoding result (except for decoding part), + /// but should be significantly more performant. + /// + /// Note that non-decoded textual contents of the current token + /// are not guaranteed to be accessible after this method + /// is called. Current implementation, for example, clears up + /// textual content during decoding. + /// Decoded binary content, however, will be retained until + /// parser is advanced to the next event. + ///@param bv Expected variant of base64 encoded + /// content (see Base64Variants for definitions + /// of "standard" variants). + ///@return Decoded binary data + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + jni.JArray getBinaryValue( + jni.JObject bv, + ) { + return const jni.JArrayType(jni.jbyteType()).fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_getBinaryValue, + jni.JniCallType.objectType, [bv.reference]).object); + } + + static final _id_getBinaryValue1 = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"getBinaryValue", r"()[B"); + + /// from: public byte[] getBinaryValue() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Convenience alternative to \#getBinaryValue(Base64Variant) + /// that defaults to using + /// Base64Variants\#getDefaultVariant as the default encoding. + ///@return Decoded binary data + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + jni.JArray getBinaryValue1() { + return const jni.JArrayType(jni.jbyteType()).fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_getBinaryValue1, + jni.JniCallType.objectType, []).object); + } + + static final _id_readBinaryValue = jni.Jni.accessors.getMethodIDOf( + _class.reference, r"readBinaryValue", r"(Ljava/io/OutputStream;)I"); + + /// from: public int readBinaryValue(java.io.OutputStream out) + /// + /// Method that can be used as an alternative to \#getBigIntegerValue(), + /// especially when value can be large. The main difference (beyond method + /// of returning content using OutputStream instead of as byte array) + /// is that content will NOT remain accessible after method returns: any content + /// processed will be consumed and is not buffered in any way. If caller needs + /// buffering, it has to implement it. + ///@param out Output stream to use for passing decoded binary data + ///@return Number of bytes that were decoded and written via OutputStream + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + ///@since 2.1 + int readBinaryValue( + jni.JObject out, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_readBinaryValue, + jni.JniCallType.intType, [out.reference]).integer; + } + + static final _id_readBinaryValue1 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"readBinaryValue", + r"(Lcom/fasterxml/jackson/core/Base64Variant;Ljava/io/OutputStream;)I"); + + /// from: public int readBinaryValue(com.fasterxml.jackson.core.Base64Variant bv, java.io.OutputStream out) + /// + /// Similar to \#readBinaryValue(OutputStream) but allows explicitly + /// specifying base64 variant to use. + ///@param bv base64 variant to use + ///@param out Output stream to use for passing decoded binary data + ///@return Number of bytes that were decoded and written via OutputStream + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + ///@since 2.1 + int readBinaryValue1( + jni.JObject bv, + jni.JObject out, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_readBinaryValue1, + jni.JniCallType.intType, [bv.reference, out.reference]).integer; + } + + static final _id_getValueAsInt = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"getValueAsInt", r"()I"); + + /// from: public int getValueAsInt() + /// + /// Method that will try to convert value of current token to a + /// Java {@code int} value. + /// Numbers are coerced using default Java rules; booleans convert to 0 (false) + /// and 1 (true), and Strings are parsed using default Java language integer + /// parsing rules. + /// + /// If representation can not be converted to an int (including structured type + /// markers like start/end Object/Array) + /// default value of __0__ will be returned; no exceptions are thrown. + ///@return {@code int} value current token is converted to, if possible; exception thrown + /// otherwise + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + int getValueAsInt() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_getValueAsInt, jni.JniCallType.intType, []).integer; + } + + static final _id_getValueAsInt1 = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"getValueAsInt", r"(I)I"); + + /// from: public int getValueAsInt(int def) + /// + /// Method that will try to convert value of current token to a + /// __int__. + /// Numbers are coerced using default Java rules; booleans convert to 0 (false) + /// and 1 (true), and Strings are parsed using default Java language integer + /// parsing rules. + /// + /// If representation can not be converted to an int (including structured type + /// markers like start/end Object/Array) + /// specified __def__ will be returned; no exceptions are thrown. + ///@param def Default value to return if conversion to {@code int} is not possible + ///@return {@code int} value current token is converted to, if possible; {@code def} otherwise + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + int getValueAsInt1( + int def, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_getValueAsInt1, + jni.JniCallType.intType, [jni.JValueInt(def)]).integer; + } + + static final _id_getValueAsLong = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"getValueAsLong", r"()J"); + + /// from: public long getValueAsLong() + /// + /// Method that will try to convert value of current token to a + /// __long__. + /// Numbers are coerced using default Java rules; booleans convert to 0 (false) + /// and 1 (true), and Strings are parsed using default Java language integer + /// parsing rules. + /// + /// If representation can not be converted to a long (including structured type + /// markers like start/end Object/Array) + /// default value of __0L__ will be returned; no exceptions are thrown. + ///@return {@code long} value current token is converted to, if possible; exception thrown + /// otherwise + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + int getValueAsLong() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_getValueAsLong, jni.JniCallType.longType, []).long; + } + + static final _id_getValueAsLong1 = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"getValueAsLong", r"(J)J"); + + /// from: public long getValueAsLong(long def) + /// + /// Method that will try to convert value of current token to a + /// __long__. + /// Numbers are coerced using default Java rules; booleans convert to 0 (false) + /// and 1 (true), and Strings are parsed using default Java language integer + /// parsing rules. + /// + /// If representation can not be converted to a long (including structured type + /// markers like start/end Object/Array) + /// specified __def__ will be returned; no exceptions are thrown. + ///@param def Default value to return if conversion to {@code long} is not possible + ///@return {@code long} value current token is converted to, if possible; {@code def} otherwise + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + int getValueAsLong1( + int def, + ) { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_getValueAsLong1, jni.JniCallType.longType, [def]).long; + } + + static final _id_getValueAsDouble = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"getValueAsDouble", r"()D"); + + /// from: public double getValueAsDouble() + /// + /// Method that will try to convert value of current token to a Java + /// __double__. + /// Numbers are coerced using default Java rules; booleans convert to 0.0 (false) + /// and 1.0 (true), and Strings are parsed using default Java language floating + /// point parsing rules. + /// + /// If representation can not be converted to a double (including structured types + /// like Objects and Arrays), + /// default value of __0.0__ will be returned; no exceptions are thrown. + ///@return {@code double} value current token is converted to, if possible; exception thrown + /// otherwise + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + double getValueAsDouble() { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_getValueAsDouble, + jni.JniCallType.doubleType, []).doubleFloat; + } + + static final _id_getValueAsDouble1 = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"getValueAsDouble", r"(D)D"); + + /// from: public double getValueAsDouble(double def) + /// + /// Method that will try to convert value of current token to a + /// Java __double__. + /// Numbers are coerced using default Java rules; booleans convert to 0.0 (false) + /// and 1.0 (true), and Strings are parsed using default Java language floating + /// point parsing rules. + /// + /// If representation can not be converted to a double (including structured types + /// like Objects and Arrays), + /// specified __def__ will be returned; no exceptions are thrown. + ///@param def Default value to return if conversion to {@code double} is not possible + ///@return {@code double} value current token is converted to, if possible; {@code def} otherwise + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + double getValueAsDouble1( + double def, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, + _id_getValueAsDouble1, jni.JniCallType.doubleType, [def]).doubleFloat; + } + + static final _id_getValueAsBoolean = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"getValueAsBoolean", r"()Z"); + + /// from: public boolean getValueAsBoolean() + /// + /// Method that will try to convert value of current token to a + /// __boolean__. + /// JSON booleans map naturally; integer numbers other than 0 map to true, and + /// 0 maps to false + /// and Strings 'true' and 'false' map to corresponding values. + /// + /// If representation can not be converted to a boolean value (including structured types + /// like Objects and Arrays), + /// default value of __false__ will be returned; no exceptions are thrown. + ///@return {@code boolean} value current token is converted to, if possible; exception thrown + /// otherwise + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + bool getValueAsBoolean() { + return jni.Jni.accessors.callMethodWithArgs(reference, + _id_getValueAsBoolean, jni.JniCallType.booleanType, []).boolean; + } + + static final _id_getValueAsBoolean1 = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"getValueAsBoolean", r"(Z)Z"); + + /// from: public boolean getValueAsBoolean(boolean def) + /// + /// Method that will try to convert value of current token to a + /// __boolean__. + /// JSON booleans map naturally; integer numbers other than 0 map to true, and + /// 0 maps to false + /// and Strings 'true' and 'false' map to corresponding values. + /// + /// If representation can not be converted to a boolean value (including structured types + /// like Objects and Arrays), + /// specified __def__ will be returned; no exceptions are thrown. + ///@param def Default value to return if conversion to {@code boolean} is not possible + ///@return {@code boolean} value current token is converted to, if possible; {@code def} otherwise + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + bool getValueAsBoolean1( + bool def, + ) { + return jni.Jni.accessors.callMethodWithArgs( + reference, + _id_getValueAsBoolean1, + jni.JniCallType.booleanType, + [def ? 1 : 0]).boolean; + } + + static final _id_getValueAsString = jni.Jni.accessors.getMethodIDOf( + _class.reference, r"getValueAsString", r"()Ljava/lang/String;"); + + /// from: public java.lang.String getValueAsString() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that will try to convert value of current token to a + /// java.lang.String. + /// JSON Strings map naturally; scalar values get converted to + /// their textual representation. + /// If representation can not be converted to a String value (including structured types + /// like Objects and Arrays and {@code null} token), default value of + /// __null__ will be returned; no exceptions are thrown. + ///@return String value current token is converted to, if possible; {@code null} otherwise + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + ///@since 2.1 + jni.JString getValueAsString() { + return const jni.JStringType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_getValueAsString, + jni.JniCallType.objectType, []).object); + } + + static final _id_getValueAsString1 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"getValueAsString", + r"(Ljava/lang/String;)Ljava/lang/String;"); + + /// from: public abstract java.lang.String getValueAsString(java.lang.String def) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that will try to convert value of current token to a + /// java.lang.String. + /// JSON Strings map naturally; scalar values get converted to + /// their textual representation. + /// If representation can not be converted to a String value (including structured types + /// like Objects and Arrays and {@code null} token), specified default value + /// will be returned; no exceptions are thrown. + ///@param def Default value to return if conversion to {@code String} is not possible + ///@return String value current token is converted to, if possible; {@code def} otherwise + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + ///@since 2.1 + jni.JString getValueAsString1( + jni.JString def, + ) { + return const jni.JStringType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_getValueAsString1, + jni.JniCallType.objectType, + [def.reference]).object); + } + + static final _id_canReadObjectId = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"canReadObjectId", r"()Z"); + + /// from: public boolean canReadObjectId() + /// + /// Introspection method that may be called to see if the underlying + /// data format supports some kind of Object Ids natively (many do not; + /// for example, JSON doesn't). + /// + /// Default implementation returns true; overridden by data formats + /// that do support native Object Ids. Caller is expected to either + /// use a non-native notation (explicit property or such), or fail, + /// in case it can not use native object ids. + ///@return {@code True} if the format being read supports native Object Ids; + /// {@code false} if not + ///@since 2.3 + bool canReadObjectId() { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_canReadObjectId, + jni.JniCallType.booleanType, []).boolean; + } + + static final _id_canReadTypeId = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"canReadTypeId", r"()Z"); + + /// from: public boolean canReadTypeId() + /// + /// Introspection method that may be called to see if the underlying + /// data format supports some kind of Type Ids natively (many do not; + /// for example, JSON doesn't). + /// + /// Default implementation returns true; overridden by data formats + /// that do support native Type Ids. Caller is expected to either + /// use a non-native notation (explicit property or such), or fail, + /// in case it can not use native type ids. + ///@return {@code True} if the format being read supports native Type Ids; + /// {@code false} if not + ///@since 2.3 + bool canReadTypeId() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_canReadTypeId, jni.JniCallType.booleanType, []).boolean; + } + + static final _id_getObjectId = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"getObjectId", r"()Ljava/lang/Object;"); + + /// from: public java.lang.Object getObjectId() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that can be called to check whether current token + /// (one that was just read) has an associated Object id, and if + /// so, return it. + /// Note that while typically caller should check with \#canReadObjectId + /// first, it is not illegal to call this method even if that method returns + /// true; but if so, it will return null. This may be used to simplify calling + /// code. + /// + /// Default implementation will simply return null. + ///@return Native Object id associated with the current token, if any; {@code null} if none + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + ///@since 2.3 + jni.JObject getObjectId() { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, _id_getObjectId, jni.JniCallType.objectType, []).object); + } + + static final _id_getTypeId = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"getTypeId", r"()Ljava/lang/Object;"); + + /// from: public java.lang.Object getTypeId() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method that can be called to check whether current token + /// (one that was just read) has an associated type id, and if + /// so, return it. + /// Note that while typically caller should check with \#canReadTypeId + /// first, it is not illegal to call this method even if that method returns + /// true; but if so, it will return null. This may be used to simplify calling + /// code. + /// + /// Default implementation will simply return null. + ///@return Native Type Id associated with the current token, if any; {@code null} if none + ///@throws IOException for low-level read issues, or + /// JsonParseException for decoding problems + ///@since 2.3 + jni.JObject getTypeId() { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, _id_getTypeId, jni.JniCallType.objectType, []).object); + } + + static final _id_readValueAs = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"readValueAs", + r"(Ljava/lang/Class;)Ljava/lang/Object;"); + + /// from: public T readValueAs(java.lang.Class valueType) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method to deserialize JSON content into a non-container + /// type (it can be an array type, however): typically a bean, array + /// or a wrapper type (like java.lang.Boolean). + /// __Note__: method can only be called if the parser has + /// an object codec assigned; this is true for parsers constructed + /// by MappingJsonFactory (from "jackson-databind" jar) + /// but not for JsonFactory (unless its setCodec + /// method has been explicitly called). + /// + /// This method may advance the event stream, for structured types + /// the current token will be the closing end marker (END_ARRAY, + /// END_OBJECT) of the bound structure. For non-structured Json types + /// (and for JsonToken\#VALUE_EMBEDDED_OBJECT) + /// stream is not advanced. + /// + /// Note: this method should NOT be used if the result type is a + /// container (java.util.Collection or java.util.Map. + /// The reason is that due to type erasure, key and value types + /// can not be introspected when using this method. + ///@param Nominal type parameter for value type + ///@param valueType Java type to read content as (passed to ObjectCodec that + /// deserializes content) + ///@return Java value read from content + ///@throws IOException if there is either an underlying I/O problem or decoding + /// issue at format layer + $T readValueAs<$T extends jni.JObject>( + jni.JObject valueType, { + required jni.JObjType<$T> T, + }) { + return T.fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_readValueAs, + jni.JniCallType.objectType, + [valueType.reference]).object); + } + + static final _id_readValueAs1 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"readValueAs", + r"(Lcom/fasterxml/jackson/core/type/TypeReference;)Ljava/lang/Object;"); + + /// from: public T readValueAs(com.fasterxml.jackson.core.type.TypeReference valueTypeRef) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method to deserialize JSON content into a Java type, reference + /// to which is passed as argument. Type is passed using so-called + /// "super type token" + /// and specifically needs to be used if the root type is a + /// parameterized (generic) container type. + /// __Note__: method can only be called if the parser has + /// an object codec assigned; this is true for parsers constructed + /// by MappingJsonFactory (defined in 'jackson-databind' bundle) + /// but not for JsonFactory (unless its setCodec + /// method has been explicitly called). + /// + /// This method may advance the event stream, for structured types + /// the current token will be the closing end marker (END_ARRAY, + /// END_OBJECT) of the bound structure. For non-structured Json types + /// (and for JsonToken\#VALUE_EMBEDDED_OBJECT) + /// stream is not advanced. + ///@param Nominal type parameter for value type + ///@param valueTypeRef Java type to read content as (passed to ObjectCodec that + /// deserializes content) + ///@return Java value read from content + ///@throws IOException if there is either an underlying I/O problem or decoding + /// issue at format layer + $T readValueAs1<$T extends jni.JObject>( + jni.JObject valueTypeRef, { + required jni.JObjType<$T> T, + }) { + return T.fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_readValueAs1, + jni.JniCallType.objectType, + [valueTypeRef.reference]).object); + } + + static final _id_readValuesAs = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"readValuesAs", + r"(Ljava/lang/Class;)Ljava/util/Iterator;"); + + /// from: public java.util.Iterator readValuesAs(java.lang.Class valueType) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for reading sequence of Objects from parser stream, + /// all with same specified value type. + ///@param Nominal type parameter for value type + ///@param valueType Java type to read content as (passed to ObjectCodec that + /// deserializes content) + ///@return Iterator for reading multiple Java values from content + ///@throws IOException if there is either an underlying I/O problem or decoding + /// issue at format layer + jni.JIterator<$T> readValuesAs<$T extends jni.JObject>( + jni.JObject valueType, { + required jni.JObjType<$T> T, + }) { + return jni.JIteratorType(T).fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_readValuesAs, + jni.JniCallType.objectType, + [valueType.reference]).object); + } + + static final _id_readValuesAs1 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"readValuesAs", + r"(Lcom/fasterxml/jackson/core/type/TypeReference;)Ljava/util/Iterator;"); + + /// from: public java.util.Iterator readValuesAs(com.fasterxml.jackson.core.type.TypeReference valueTypeRef) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method for reading sequence of Objects from parser stream, + /// all with same specified value type. + ///@param Nominal type parameter for value type + ///@param valueTypeRef Java type to read content as (passed to ObjectCodec that + /// deserializes content) + ///@return Iterator for reading multiple Java values from content + ///@throws IOException if there is either an underlying I/O problem or decoding + /// issue at format layer + jni.JIterator<$T> readValuesAs1<$T extends jni.JObject>( + jni.JObject valueTypeRef, { + required jni.JObjType<$T> T, + }) { + return jni.JIteratorType(T).fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_readValuesAs1, + jni.JniCallType.objectType, + [valueTypeRef.reference]).object); + } + + static final _id_readValueAsTree = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"readValueAsTree", + r"()Lcom/fasterxml/jackson/core/TreeNode;"); + + /// from: public T readValueAsTree() + /// The returned object must be released after use, by calling the [release] method. + /// + /// Method to deserialize JSON content into equivalent "tree model", + /// represented by root TreeNode of resulting model. + /// For JSON Arrays it will an array node (with child nodes), + /// for objects object node (with child nodes), and for other types + /// matching leaf node type. Empty or whitespace documents are null. + ///@param Nominal type parameter for result node type (to reduce need for casting) + ///@return root of the document, or null if empty or whitespace. + ///@throws IOException if there is either an underlying I/O problem or decoding + /// issue at format layer + $T readValueAsTree<$T extends jni.JObject>({ + required jni.JObjType<$T> T, + }) { + return T.fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, _id_readValueAsTree, jni.JniCallType.objectType, []).object); + } +} + +final class $JsonParserType extends jni.JObjType { + const $JsonParserType(); + + @override + String get signature => r"Lcom/fasterxml/jackson/core/JsonParser;"; + + @override + JsonParser fromRef(jni.JObjectPtr ref) => JsonParser.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($JsonParserType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($JsonParserType) && other is $JsonParserType; + } +} + +/// from: com.fasterxml.jackson.core.JsonParser$Feature +/// +/// Enumeration that defines all on/off features for parsers. +class JsonParser_Feature extends jni.JObject { + @override + late final jni.JObjType $type = type; + + JsonParser_Feature.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = + jni.Jni.findJClass(r"com/fasterxml/jackson/core/JsonParser$Feature"); + + /// The type which includes information such as the signature of this class. + static const type = $JsonParser_FeatureType(); + static final _id_values = jni.Jni.accessors.getStaticMethodIDOf( + _class.reference, + r"values", + r"()[Lcom/fasterxml/jackson/core/JsonParser$Feature;"); + + /// from: static public com.fasterxml.jackson.core.JsonParser.Feature[] values() + /// The returned object must be released after use, by calling the [release] method. + static jni.JArray values() { + return const jni.JArrayType($JsonParser_FeatureType()).fromRef( + jni.Jni.accessors.callStaticMethodWithArgs(_class.reference, _id_values, + jni.JniCallType.objectType, []).object); + } + + static final _id_valueOf = jni.Jni.accessors.getStaticMethodIDOf( + _class.reference, + r"valueOf", + r"(Ljava/lang/String;)Lcom/fasterxml/jackson/core/JsonParser$Feature;"); + + /// from: static public com.fasterxml.jackson.core.JsonParser.Feature valueOf(java.lang.String name) + /// The returned object must be released after use, by calling the [release] method. + static JsonParser_Feature valueOf( + jni.JString name, + ) { + return const $JsonParser_FeatureType().fromRef(jni.Jni.accessors + .callStaticMethodWithArgs(_class.reference, _id_valueOf, + jni.JniCallType.objectType, [name.reference]).object); + } + + static final _id_collectDefaults = jni.Jni.accessors + .getStaticMethodIDOf(_class.reference, r"collectDefaults", r"()I"); + + /// from: static public int collectDefaults() + /// + /// Method that calculates bit set (flags) of all features that + /// are enabled by default. + ///@return Bit mask of all features that are enabled by default + static int collectDefaults() { + return jni.Jni.accessors.callStaticMethodWithArgs(_class.reference, + _id_collectDefaults, jni.JniCallType.intType, []).integer; + } + + static final _id_enabledByDefault = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"enabledByDefault", r"()Z"); + + /// from: public boolean enabledByDefault() + bool enabledByDefault() { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_enabledByDefault, + jni.JniCallType.booleanType, []).boolean; + } + + static final _id_enabledIn = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"enabledIn", r"(I)Z"); + + /// from: public boolean enabledIn(int flags) + bool enabledIn( + int flags, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_enabledIn, + jni.JniCallType.booleanType, [jni.JValueInt(flags)]).boolean; + } + + static final _id_getMask = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"getMask", r"()I"); + + /// from: public int getMask() + int getMask() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_getMask, jni.JniCallType.intType, []).integer; + } +} + +final class $JsonParser_FeatureType extends jni.JObjType { + const $JsonParser_FeatureType(); + + @override + String get signature => r"Lcom/fasterxml/jackson/core/JsonParser$Feature;"; + + @override + JsonParser_Feature fromRef(jni.JObjectPtr ref) => + JsonParser_Feature.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($JsonParser_FeatureType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($JsonParser_FeatureType) && + other is $JsonParser_FeatureType; + } +} + +/// from: com.fasterxml.jackson.core.JsonParser$NumberType +/// +/// Enumeration of possible "native" (optimal) types that can be +/// used for numbers. +class JsonParser_NumberType extends jni.JObject { + @override + late final jni.JObjType $type = type; + + JsonParser_NumberType.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = + jni.Jni.findJClass(r"com/fasterxml/jackson/core/JsonParser$NumberType"); + + /// The type which includes information such as the signature of this class. + static const type = $JsonParser_NumberTypeType(); + static final _id_values = jni.Jni.accessors.getStaticMethodIDOf( + _class.reference, + r"values", + r"()[Lcom/fasterxml/jackson/core/JsonParser$NumberType;"); + + /// from: static public com.fasterxml.jackson.core.JsonParser.NumberType[] values() + /// The returned object must be released after use, by calling the [release] method. + static jni.JArray values() { + return const jni.JArrayType($JsonParser_NumberTypeType()).fromRef( + jni.Jni.accessors.callStaticMethodWithArgs(_class.reference, _id_values, + jni.JniCallType.objectType, []).object); + } + + static final _id_valueOf = jni.Jni.accessors.getStaticMethodIDOf( + _class.reference, + r"valueOf", + r"(Ljava/lang/String;)Lcom/fasterxml/jackson/core/JsonParser$NumberType;"); + + /// from: static public com.fasterxml.jackson.core.JsonParser.NumberType valueOf(java.lang.String name) + /// The returned object must be released after use, by calling the [release] method. + static JsonParser_NumberType valueOf( + jni.JString name, + ) { + return const $JsonParser_NumberTypeType().fromRef(jni.Jni.accessors + .callStaticMethodWithArgs(_class.reference, _id_valueOf, + jni.JniCallType.objectType, [name.reference]).object); + } +} + +final class $JsonParser_NumberTypeType + extends jni.JObjType { + const $JsonParser_NumberTypeType(); + + @override + String get signature => r"Lcom/fasterxml/jackson/core/JsonParser$NumberType;"; + + @override + JsonParser_NumberType fromRef(jni.JObjectPtr ref) => + JsonParser_NumberType.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($JsonParser_NumberTypeType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($JsonParser_NumberTypeType) && + other is $JsonParser_NumberTypeType; + } +} diff --git a/pkgs/jnigen/test/jackson_core_test/third_party/dart_only/dart_bindings/com/fasterxml/jackson/core/JsonToken.dart b/pkgs/jnigen/test/jackson_core_test/third_party/dart_only/dart_bindings/com/fasterxml/jackson/core/JsonToken.dart new file mode 100644 index 000000000..573a815ac --- /dev/null +++ b/pkgs/jnigen/test/jackson_core_test/third_party/dart_only/dart_bindings/com/fasterxml/jackson/core/JsonToken.dart @@ -0,0 +1,224 @@ +// Generated from jackson-core which is licensed under the Apache License 2.0. +// The following copyright from the original authors applies. +// See https://github.com/FasterXML/jackson-core/blob/2.14/LICENSE +// +// Copyright (c) 2007 - The Jackson Project Authors +// Licensed under the Apache License, Version 2.0 (the "License") +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Autogenerated by jnigen. DO NOT EDIT! + +// ignore_for_file: annotate_overrides +// ignore_for_file: camel_case_extensions +// ignore_for_file: camel_case_types +// ignore_for_file: constant_identifier_names +// ignore_for_file: file_names +// ignore_for_file: lines_longer_than_80_chars +// ignore_for_file: no_leading_underscores_for_local_identifiers +// ignore_for_file: non_constant_identifier_names +// ignore_for_file: overridden_fields +// ignore_for_file: unnecessary_cast +// ignore_for_file: unused_element +// ignore_for_file: unused_field +// ignore_for_file: unused_import +// ignore_for_file: unused_local_variable +// ignore_for_file: unused_shown_name + +import "dart:isolate" show ReceivePort; +import "dart:ffi" as ffi; +import "package:jni/internal_helpers_for_jnigen.dart"; +import "package:jni/jni.dart" as jni; + +/// from: com.fasterxml.jackson.core.JsonToken +/// +/// Enumeration for basic token types used for returning results +/// of parsing JSON content. +class JsonToken extends jni.JObject { + @override + late final jni.JObjType $type = type; + + JsonToken.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = + jni.Jni.findJClass(r"com/fasterxml/jackson/core/JsonToken"); + + /// The type which includes information such as the signature of this class. + static const type = $JsonTokenType(); + static final _id_values = jni.Jni.accessors.getStaticMethodIDOf( + _class.reference, + r"values", + r"()[Lcom/fasterxml/jackson/core/JsonToken;"); + + /// from: static public com.fasterxml.jackson.core.JsonToken[] values() + /// The returned object must be released after use, by calling the [release] method. + static jni.JArray values() { + return const jni.JArrayType($JsonTokenType()).fromRef(jni.Jni.accessors + .callStaticMethodWithArgs(_class.reference, _id_values, + jni.JniCallType.objectType, []).object); + } + + static final _id_valueOf = jni.Jni.accessors.getStaticMethodIDOf( + _class.reference, + r"valueOf", + r"(Ljava/lang/String;)Lcom/fasterxml/jackson/core/JsonToken;"); + + /// from: static public com.fasterxml.jackson.core.JsonToken valueOf(java.lang.String name) + /// The returned object must be released after use, by calling the [release] method. + static JsonToken valueOf( + jni.JString name, + ) { + return const $JsonTokenType().fromRef(jni.Jni.accessors + .callStaticMethodWithArgs(_class.reference, _id_valueOf, + jni.JniCallType.objectType, [name.reference]).object); + } + + static final _id_id = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"id", r"()I"); + + /// from: public final int id() + int id() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_id, jni.JniCallType.intType, []).integer; + } + + static final _id_asString = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"asString", r"()Ljava/lang/String;"); + + /// from: public final java.lang.String asString() + /// The returned object must be released after use, by calling the [release] method. + jni.JString asString() { + return const jni.JStringType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, _id_asString, jni.JniCallType.objectType, []).object); + } + + static final _id_asCharArray = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"asCharArray", r"()[C"); + + /// from: public final char[] asCharArray() + /// The returned object must be released after use, by calling the [release] method. + jni.JArray asCharArray() { + return const jni.JArrayType(jni.jcharType()).fromRef(jni.Jni.accessors + .callMethodWithArgs( + reference, _id_asCharArray, jni.JniCallType.objectType, []).object); + } + + static final _id_asByteArray = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"asByteArray", r"()[B"); + + /// from: public final byte[] asByteArray() + /// The returned object must be released after use, by calling the [release] method. + jni.JArray asByteArray() { + return const jni.JArrayType(jni.jbyteType()).fromRef(jni.Jni.accessors + .callMethodWithArgs( + reference, _id_asByteArray, jni.JniCallType.objectType, []).object); + } + + static final _id_isNumeric = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"isNumeric", r"()Z"); + + /// from: public final boolean isNumeric() + /// + /// @return {@code True} if this token is {@code VALUE_NUMBER_INT} or {@code VALUE_NUMBER_FLOAT}, + /// {@code false} otherwise + bool isNumeric() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_isNumeric, jni.JniCallType.booleanType, []).boolean; + } + + static final _id_isStructStart = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"isStructStart", r"()Z"); + + /// from: public final boolean isStructStart() + /// + /// Accessor that is functionally equivalent to: + /// + /// this == JsonToken.START_OBJECT || this == JsonToken.START_ARRAY + /// + ///@return {@code True} if this token is {@code START_OBJECT} or {@code START_ARRAY}, + /// {@code false} otherwise + ///@since 2.3 + bool isStructStart() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_isStructStart, jni.JniCallType.booleanType, []).boolean; + } + + static final _id_isStructEnd = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"isStructEnd", r"()Z"); + + /// from: public final boolean isStructEnd() + /// + /// Accessor that is functionally equivalent to: + /// + /// this == JsonToken.END_OBJECT || this == JsonToken.END_ARRAY + /// + ///@return {@code True} if this token is {@code END_OBJECT} or {@code END_ARRAY}, + /// {@code false} otherwise + ///@since 2.3 + bool isStructEnd() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_isStructEnd, jni.JniCallType.booleanType, []).boolean; + } + + static final _id_isScalarValue = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"isScalarValue", r"()Z"); + + /// from: public final boolean isScalarValue() + /// + /// Method that can be used to check whether this token represents + /// a valid non-structured value. This means all {@code VALUE_xxx} tokens; + /// excluding {@code START_xxx} and {@code END_xxx} tokens as well + /// {@code FIELD_NAME}. + ///@return {@code True} if this token is a scalar value token (one of + /// {@code VALUE_xxx} tokens), {@code false} otherwise + bool isScalarValue() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_isScalarValue, jni.JniCallType.booleanType, []).boolean; + } + + static final _id_isBoolean = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"isBoolean", r"()Z"); + + /// from: public final boolean isBoolean() + /// + /// @return {@code True} if this token is {@code VALUE_TRUE} or {@code VALUE_FALSE}, + /// {@code false} otherwise + bool isBoolean() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_isBoolean, jni.JniCallType.booleanType, []).boolean; + } +} + +final class $JsonTokenType extends jni.JObjType { + const $JsonTokenType(); + + @override + String get signature => r"Lcom/fasterxml/jackson/core/JsonToken;"; + + @override + JsonToken fromRef(jni.JObjectPtr ref) => JsonToken.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($JsonTokenType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($JsonTokenType) && other is $JsonTokenType; + } +} diff --git a/pkgs/jnigen/test/jackson_core_test/third_party/dart_only/dart_bindings/com/fasterxml/jackson/core/_package.dart b/pkgs/jnigen/test/jackson_core_test/third_party/dart_only/dart_bindings/com/fasterxml/jackson/core/_package.dart new file mode 100644 index 000000000..cae2a52e6 --- /dev/null +++ b/pkgs/jnigen/test/jackson_core_test/third_party/dart_only/dart_bindings/com/fasterxml/jackson/core/_package.dart @@ -0,0 +1,3 @@ +export "JsonFactory.dart"; +export "JsonParser.dart"; +export "JsonToken.dart"; diff --git a/pkgs/jnigen/test/kotlin_test/.gitignore b/pkgs/jnigen/test/kotlin_test/.gitignore new file mode 100644 index 000000000..39de10f73 --- /dev/null +++ b/pkgs/jnigen/test/kotlin_test/.gitignore @@ -0,0 +1,5 @@ +build/ +*.class +test_lib/ +test_src/ +target/ diff --git a/pkgs/jnigen/test/kotlin_test/c_based/c_bindings/.clang-format b/pkgs/jnigen/test/kotlin_test/c_based/c_bindings/.clang-format new file mode 100644 index 000000000..a256c2f09 --- /dev/null +++ b/pkgs/jnigen/test/kotlin_test/c_based/c_bindings/.clang-format @@ -0,0 +1,15 @@ +# From dart SDK: https://github.com/dart-lang/sdk/blob/main/.clang-format + +# Defines the Chromium style for automatic reformatting. +# http://clang.llvm.org/docs/ClangFormatStyleOptions.html +BasedOnStyle: Chromium + +# clang-format doesn't seem to do a good job of this for longer comments. +ReflowComments: 'false' + +# We have lots of these. Though we need to put them all in curly braces, +# clang-format can't do that. +AllowShortIfStatementsOnASingleLine: 'true' + +# Put escaped newlines into the rightmost column. +AlignEscapedNewlinesLeft: false diff --git a/pkgs/jnigen/test/kotlin_test/c_based/c_bindings/CMakeLists.txt b/pkgs/jnigen/test/kotlin_test/c_based/c_bindings/CMakeLists.txt new file mode 100644 index 000000000..3889f546a --- /dev/null +++ b/pkgs/jnigen/test/kotlin_test/c_based/c_bindings/CMakeLists.txt @@ -0,0 +1,32 @@ +# jni_native_build (Build with jni:setup. Do not delete this line.) + +# The Flutter tooling requires that developers have CMake 3.10 or later +# installed. You should not increase this version, as doing so will cause +# the plugin to fail to compile for some customers of the plugin. +cmake_minimum_required(VERSION 3.10) + +project(kotlin VERSION 0.0.1 LANGUAGES C) + +add_library(kotlin SHARED + "./kotlin.c" +) + +set_target_properties(kotlin PROPERTIES + OUTPUT_NAME "kotlin" +) + +target_compile_definitions(kotlin PUBLIC DART_SHARED_LIB) + +if(WIN32) + set_target_properties(${TARGET_NAME} PROPERTIES + LINK_FLAGS "/DELAYLOAD:jvm.dll") +endif() + +if (ANDROID) + target_link_libraries(kotlin log) +else() + find_package(Java REQUIRED) + find_package(JNI REQUIRED) + include_directories(${JNI_INCLUDE_DIRS}) + target_link_libraries(kotlin ${JNI_LIBRARIES}) +endif() diff --git a/pkgs/jnigen/test/kotlin_test/c_based/c_bindings/dartjni.h b/pkgs/jnigen/test/kotlin_test/c_based/c_bindings/dartjni.h new file mode 100644 index 000000000..8f1dc7481 --- /dev/null +++ b/pkgs/jnigen/test/kotlin_test/c_based/c_bindings/dartjni.h @@ -0,0 +1,424 @@ +// 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. + +#pragma once + +// Note: include appropriate system jni.h as found by CMake, not third_party/jni.h. +#include +#include +#include +#include + +#if _WIN32 +#include +#else +#include +#include +#endif + +#if _WIN32 +#define FFI_PLUGIN_EXPORT __declspec(dllexport) +#else +#define FFI_PLUGIN_EXPORT +#endif + +#if defined _WIN32 +#define thread_local __declspec(thread) +#else +#define thread_local __thread +#endif + +#ifdef __ANDROID__ +#include +#endif + +#ifdef __ANDROID__ +#define __ENVP_CAST (JNIEnv**) +#else +#define __ENVP_CAST (void**) +#endif + +/// Locking functions for windows and pthread. + +#if defined _WIN32 +#include + +typedef CRITICAL_SECTION MutexLock; +typedef CONDITION_VARIABLE ConditionVariable; + +static inline void init_lock(MutexLock* lock) { + InitializeCriticalSection(lock); +} + +static inline void acquire_lock(MutexLock* lock) { + EnterCriticalSection(lock); +} + +static inline void release_lock(MutexLock* lock) { + LeaveCriticalSection(lock); +} + +static inline void destroy_lock(MutexLock* lock) { + DeleteCriticalSection(lock); +} + +static inline void init_cond(ConditionVariable* cond) { + InitializeConditionVariable(cond); +} + +static inline void signal_cond(ConditionVariable* cond) { + WakeConditionVariable(cond); +} + +static inline void wait_for(ConditionVariable* cond, MutexLock* lock) { + SleepConditionVariableCS(cond, lock, INFINITE); +} + +static inline void destroy_cond(ConditionVariable* cond) { + // Not available. +} + +#elif defined __APPLE__ || defined __LINUX__ || defined __ANDROID__ || \ + defined __GNUC__ +#include + +typedef pthread_mutex_t MutexLock; +typedef pthread_cond_t ConditionVariable; + +static inline void init_lock(MutexLock* lock) { + pthread_mutex_init(lock, NULL); +} + +static inline void acquire_lock(MutexLock* lock) { + pthread_mutex_lock(lock); +} + +static inline void release_lock(MutexLock* lock) { + pthread_mutex_unlock(lock); +} + +static inline void destroy_lock(MutexLock* lock) { + pthread_mutex_destroy(lock); +} + +static inline void init_cond(ConditionVariable* cond) { + pthread_cond_init(cond, NULL); +} + +static inline void signal_cond(ConditionVariable* cond) { + pthread_cond_signal(cond); +} + +static inline void wait_for(ConditionVariable* cond, MutexLock* lock) { + pthread_cond_wait(cond, lock); +} + +static inline void destroy_cond(ConditionVariable* cond) { + pthread_cond_destroy(cond); +} + +#else + +#error "No locking/condition variable support; Possibly unsupported platform" + +#endif + +typedef struct CallbackResult { + MutexLock lock; + ConditionVariable cond; + int ready; + jobject object; +} CallbackResult; + +typedef struct JniLocks { + MutexLock classLoadingLock; + MutexLock methodLoadingLock; + MutexLock fieldLoadingLock; +} JniLocks; + +/// Represents the error when dart-jni layer has already spawned singleton VM. +#define DART_JNI_SINGLETON_EXISTS (-99); + +/// Stores the global state of the JNI. +typedef struct JniContext { + JavaVM* jvm; + jobject classLoader; + jmethodID loadClassMethod; + jobject currentActivity; + jobject appContext; + JniLocks locks; +} JniContext; + +// jniEnv for this thread, used by inline functions in this header, +// therefore declared as extern. +extern thread_local JNIEnv* jniEnv; + +extern JniContext* jni; + +/// Types used by JNI API to distinguish between primitive types. +enum JniType { + booleanType = 0, + byteType = 1, + shortType = 2, + charType = 3, + intType = 4, + longType = 5, + floatType = 6, + doubleType = 7, + objectType = 8, + voidType = 9, +}; + +/// Result type for use by JNI. +/// +/// If [exception] is null, it means the result is valid. +/// It's assumed that the caller knows the expected type in [result]. +typedef struct JniResult { + jvalue value; + jthrowable exception; +} JniResult; + +/// Similar to [JniResult] but for class lookups. +typedef struct JniClassLookupResult { + jclass value; + jthrowable exception; +} JniClassLookupResult; + +/// Similar to [JniResult] but for method/field ID lookups. +typedef struct JniPointerResult { + const void* value; + jthrowable exception; +} JniPointerResult; + +/// JniExceptionDetails holds 2 jstring objects, one is the result of +/// calling `toString` on exception object, other is stack trace; +typedef struct JniExceptionDetails { + jstring message; + jstring stacktrace; +} JniExceptionDetails; + +/// This struct contains functions which wrap method call / field access conveniently along with +/// exception checking. +/// +/// Flutter embedding checks for pending JNI exceptions before an FFI transition, which requires us +/// to check for and clear the exception before returning to dart code, which requires these functions +/// to return result types. +typedef struct JniAccessorsStruct { + JniClassLookupResult (*getClass)(char* internalName); + JniPointerResult (*getFieldID)(jclass cls, char* fieldName, char* signature); + JniPointerResult (*getStaticFieldID)(jclass cls, + char* fieldName, + char* signature); + JniPointerResult (*getMethodID)(jclass cls, + char* methodName, + char* signature); + JniPointerResult (*getStaticMethodID)(jclass cls, + char* methodName, + char* signature); + JniResult (*newObject)(jclass cls, jmethodID ctor, jvalue* args); + JniResult (*newPrimitiveArray)(jsize length, int type); + JniResult (*newObjectArray)(jsize length, + jclass elementClass, + jobject initialElement); + JniResult (*getArrayElement)(jarray array, int index, int type); + JniResult (*callMethod)(jobject obj, + jmethodID methodID, + int callType, + jvalue* args); + JniResult (*callStaticMethod)(jclass cls, + jmethodID methodID, + int callType, + jvalue* args); + JniResult (*getField)(jobject obj, jfieldID fieldID, int callType); + JniResult (*getStaticField)(jclass cls, jfieldID fieldID, int callType); + JniExceptionDetails (*getExceptionDetails)(jthrowable exception); +} JniAccessorsStruct; + +FFI_PLUGIN_EXPORT JniAccessorsStruct* GetAccessors(); + +FFI_PLUGIN_EXPORT JavaVM* GetJavaVM(void); + +FFI_PLUGIN_EXPORT JNIEnv* GetJniEnv(void); + +/// Spawn a JVM with given arguments. +/// +/// Returns JNI_OK on success, and one of the documented JNI error codes on +/// failure. It returns DART_JNI_SINGLETON_EXISTS if an attempt to spawn multiple +/// JVMs is made, even if the underlying API potentially supports multiple VMs. +FFI_PLUGIN_EXPORT int SpawnJvm(JavaVMInitArgs* args); + +/// Load class through platform-specific mechanism. +/// +/// Currently uses application classloader on android, +/// and JNIEnv->FindClass on other platforms. +FFI_PLUGIN_EXPORT jclass FindClass(const char* name); + +/// Returns Application classLoader (on Android), +/// which can be used to load application and platform classes. +/// +/// On other platforms, NULL is returned. +FFI_PLUGIN_EXPORT jobject GetClassLoader(void); + +/// Returns application context on Android. +/// +/// On other platforms, NULL is returned. +FFI_PLUGIN_EXPORT jobject GetApplicationContext(void); + +/// Returns current activity of the app on Android. +FFI_PLUGIN_EXPORT jobject GetCurrentActivity(void); + +static inline void attach_thread() { + if (jniEnv == NULL) { + (*jni->jvm)->AttachCurrentThread(jni->jvm, __ENVP_CAST & jniEnv, NULL); + } +} + +/// Load class into [cls] using platform specific mechanism +static inline void load_class_platform(jclass* cls, const char* name) { +#ifdef __ANDROID__ + jstring className = (*jniEnv)->NewStringUTF(jniEnv, name); + *cls = (*jniEnv)->CallObjectMethod(jniEnv, jni->classLoader, + jni->loadClassMethod, className); + (*jniEnv)->DeleteLocalRef(jniEnv, className); +#else + *cls = (*jniEnv)->FindClass(jniEnv, name); +#endif +} + +static inline void load_class_local_ref(jclass* cls, const char* name) { + if (*cls == NULL) { + acquire_lock(&jni->locks.classLoadingLock); + if (*cls == NULL) { + load_class_platform(cls, name); + } + release_lock(&jni->locks.classLoadingLock); + } +} + +static inline void load_class_global_ref(jclass* cls, const char* name) { + if (*cls == NULL) { + jclass tmp = NULL; + acquire_lock(&jni->locks.classLoadingLock); + if (*cls == NULL) { + load_class_platform(&tmp, name); + if (!(*jniEnv)->ExceptionCheck(jniEnv)) { + *cls = (*jniEnv)->NewGlobalRef(jniEnv, tmp); + (*jniEnv)->DeleteLocalRef(jniEnv, tmp); + } + } + release_lock(&jni->locks.classLoadingLock); + } +} + +static inline void load_method(jclass cls, + jmethodID* res, + const char* name, + const char* sig) { + if (*res == NULL) { + acquire_lock(&jni->locks.methodLoadingLock); + if (*res == NULL) { + *res = (*jniEnv)->GetMethodID(jniEnv, cls, name, sig); + } + release_lock(&jni->locks.methodLoadingLock); + } +} + +static inline void load_static_method(jclass cls, + jmethodID* res, + const char* name, + const char* sig) { + if (*res == NULL) { + acquire_lock(&jni->locks.methodLoadingLock); + if (*res == NULL) { + *res = (*jniEnv)->GetStaticMethodID(jniEnv, cls, name, sig); + } + release_lock(&jni->locks.methodLoadingLock); + } +} + +static inline void load_field(jclass cls, + jfieldID* res, + const char* name, + const char* sig) { + if (*res == NULL) { + acquire_lock(&jni->locks.fieldLoadingLock); + if (*res == NULL) { + *res = (*jniEnv)->GetFieldID(jniEnv, cls, name, sig); + } + release_lock(&jni->locks.fieldLoadingLock); + } +} + +static inline void load_static_field(jclass cls, + jfieldID* res, + const char* name, + const char* sig) { + if (*res == NULL) { + acquire_lock(&jni->locks.fieldLoadingLock); + if (*res == NULL) { + *res = (*jniEnv)->GetStaticFieldID(jniEnv, cls, name, sig); + } + release_lock(&jni->locks.fieldLoadingLock); + } +} + +static inline jobject to_global_ref(jobject ref) { + jobject g = (*jniEnv)->NewGlobalRef(jniEnv, ref); + (*jniEnv)->DeleteLocalRef(jniEnv, ref); + return g; +} + +// These functions are useful for C+Dart bindings, and not required for pure dart bindings. + +FFI_PLUGIN_EXPORT JniContext* GetJniContextPtr(); + +/// For use by jni_gen's generated code +/// don't use these. + +// these 2 fn ptr vars will be defined by generated code library +extern JniContext* (*context_getter)(void); +extern JNIEnv* (*env_getter)(void); + +// this function will be exported by generated code library +// it will set above 2 variables. +FFI_PLUGIN_EXPORT void setJniGetters(struct JniContext* (*cg)(void), + JNIEnv* (*eg)(void)); + +static inline void load_env() { + if (jniEnv == NULL) { + jni = context_getter(); + jniEnv = env_getter(); + } +} + +static inline jthrowable check_exception() { + jthrowable exception = (*jniEnv)->ExceptionOccurred(jniEnv); + if (exception != NULL) (*jniEnv)->ExceptionClear(jniEnv); + if (exception == NULL) return NULL; + return to_global_ref(exception); +} + +static inline JniResult to_global_ref_result(jobject ref) { + JniResult result; + result.exception = check_exception(); + if (result.exception == NULL) { + result.value.l = to_global_ref(ref); + } + return result; +} + +FFI_PLUGIN_EXPORT intptr_t InitDartApiDL(void* data); + +FFI_PLUGIN_EXPORT +JniResult DartException__ctor(jstring message); + +FFI_PLUGIN_EXPORT +JniResult PortContinuation__ctor(int64_t j); + +FFI_PLUGIN_EXPORT +JniResult PortProxy__newInstance(jobject binaryName, + int64_t port, + int64_t functionPtr); + +FFI_PLUGIN_EXPORT void resultFor(CallbackResult* result, jobject object); diff --git a/pkgs/jnigen/test/kotlin_test/c_based/c_bindings/kotlin.c b/pkgs/jnigen/test/kotlin_test/c_based/c_bindings/kotlin.c new file mode 100644 index 000000000..e3c227e6a --- /dev/null +++ b/pkgs/jnigen/test/kotlin_test/c_based/c_bindings/kotlin.c @@ -0,0 +1,76 @@ +// Copyright (c) 2023, 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. + +// Autogenerated by jnigen. DO NOT EDIT! + +#include +#include "dartjni.h" +#include "jni.h" + +thread_local JNIEnv* jniEnv; +JniContext* jni; + +JniContext* (*context_getter)(void); +JNIEnv* (*env_getter)(void); + +void setJniGetters(JniContext* (*cg)(void), JNIEnv* (*eg)(void)) { + context_getter = cg; + env_getter = eg; +} + +// com.github.dart_lang.jnigen.SuspendFun +jclass _c_SuspendFun = NULL; + +jmethodID _m_SuspendFun__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult SuspendFun__new0() { + load_env(); + load_class_global_ref(&_c_SuspendFun, + "com/github/dart_lang/jnigen/SuspendFun"); + if (_c_SuspendFun == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_SuspendFun, &_m_SuspendFun__new0, "", "()V"); + if (_m_SuspendFun__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->NewObject(jniEnv, _c_SuspendFun, _m_SuspendFun__new0); + return to_global_ref_result(_result); +} + +jmethodID _m_SuspendFun__sayHello = NULL; +FFI_PLUGIN_EXPORT +JniResult SuspendFun__sayHello(jobject self_, jobject continuation) { + load_env(); + load_class_global_ref(&_c_SuspendFun, + "com/github/dart_lang/jnigen/SuspendFun"); + if (_c_SuspendFun == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_SuspendFun, &_m_SuspendFun__sayHello, "sayHello", + "(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;"); + if (_m_SuspendFun__sayHello == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_SuspendFun__sayHello, continuation); + return to_global_ref_result(_result); +} + +jmethodID _m_SuspendFun__sayHello1 = NULL; +FFI_PLUGIN_EXPORT +JniResult SuspendFun__sayHello1(jobject self_, + jobject string, + jobject continuation) { + load_env(); + load_class_global_ref(&_c_SuspendFun, + "com/github/dart_lang/jnigen/SuspendFun"); + if (_c_SuspendFun == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method( + _c_SuspendFun, &_m_SuspendFun__sayHello1, "sayHello", + "(Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;"); + if (_m_SuspendFun__sayHello1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_SuspendFun__sayHello1, string, continuation); + return to_global_ref_result(_result); +} diff --git a/pkgs/jnigen/test/kotlin_test/c_based/dart_bindings/kotlin.dart b/pkgs/jnigen/test/kotlin_test/c_based/dart_bindings/kotlin.dart new file mode 100644 index 000000000..3e264274c --- /dev/null +++ b/pkgs/jnigen/test/kotlin_test/c_based/dart_bindings/kotlin.dart @@ -0,0 +1,127 @@ +// Copyright (c) 2023, 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. + +// Autogenerated by jnigen. DO NOT EDIT! + +// ignore_for_file: annotate_overrides +// ignore_for_file: camel_case_extensions +// ignore_for_file: camel_case_types +// ignore_for_file: constant_identifier_names +// ignore_for_file: file_names +// ignore_for_file: lines_longer_than_80_chars +// ignore_for_file: no_leading_underscores_for_local_identifiers +// ignore_for_file: non_constant_identifier_names +// ignore_for_file: overridden_fields +// ignore_for_file: unnecessary_cast +// ignore_for_file: unused_element +// ignore_for_file: unused_field +// ignore_for_file: unused_import +// ignore_for_file: unused_local_variable +// ignore_for_file: unused_shown_name + +import "dart:isolate" show ReceivePort; +import "dart:ffi" as ffi; +import "package:jni/internal_helpers_for_jnigen.dart"; +import "package:jni/jni.dart" as jni; + +// Auto-generated initialization code. + +final ffi.Pointer Function(String sym) jniLookup = + ProtectedJniExtensions.initGeneratedLibrary("kotlin"); + +/// from: com.github.dart_lang.jnigen.SuspendFun +class SuspendFun extends jni.JObject { + @override + late final jni.JObjType $type = type; + + SuspendFun.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $SuspendFunType(); + static final _new0 = jniLookup>( + "SuspendFun__new0") + .asFunction(); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory SuspendFun() { + return SuspendFun.fromRef(_new0().object); + } + + static final _sayHello = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("SuspendFun__sayHello") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public final java.lang.Object sayHello(kotlin.coroutines.Continuation continuation) + /// The returned object must be released after use, by calling the [release] method. + Future sayHello() async { + final $p = ReceivePort(); + final $c = + jni.JObject.fromRef(ProtectedJniExtensions.newPortContinuation($p)); + _sayHello(reference, $c.reference).object; + final $o = jni.JObjectPtr.fromAddress(await $p.first); + final $k = const jni.JStringType().getClass().reference; + if (!jni.Jni.env.IsInstanceOf($o, $k)) { + throw "Failed"; + } + return const jni.JStringType().fromRef($o); + } + + static final _sayHello1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>("SuspendFun__sayHello1") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); + + /// from: public final java.lang.Object sayHello(java.lang.String string, kotlin.coroutines.Continuation continuation) + /// The returned object must be released after use, by calling the [release] method. + Future sayHello1( + jni.JString string, + ) async { + final $p = ReceivePort(); + final $c = + jni.JObject.fromRef(ProtectedJniExtensions.newPortContinuation($p)); + _sayHello1(reference, string.reference, $c.reference).object; + final $o = jni.JObjectPtr.fromAddress(await $p.first); + final $k = const jni.JStringType().getClass().reference; + if (!jni.Jni.env.IsInstanceOf($o, $k)) { + throw "Failed"; + } + return const jni.JStringType().fromRef($o); + } +} + +final class $SuspendFunType extends jni.JObjType { + const $SuspendFunType(); + + @override + String get signature => r"Lcom/github/dart_lang/jnigen/SuspendFun;"; + + @override + SuspendFun fromRef(jni.JObjectPtr ref) => SuspendFun.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($SuspendFunType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($SuspendFunType) && other is $SuspendFunType; + } +} diff --git a/pkgs/jnigen/test/kotlin_test/dart_only/dart_bindings/kotlin.dart b/pkgs/jnigen/test/kotlin_test/dart_only/dart_bindings/kotlin.dart new file mode 100644 index 000000000..bd4441f36 --- /dev/null +++ b/pkgs/jnigen/test/kotlin_test/dart_only/dart_bindings/kotlin.dart @@ -0,0 +1,117 @@ +// Copyright (c) 2023, 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. + +// Autogenerated by jnigen. DO NOT EDIT! + +// ignore_for_file: annotate_overrides +// ignore_for_file: camel_case_extensions +// ignore_for_file: camel_case_types +// ignore_for_file: constant_identifier_names +// ignore_for_file: file_names +// ignore_for_file: lines_longer_than_80_chars +// ignore_for_file: no_leading_underscores_for_local_identifiers +// ignore_for_file: non_constant_identifier_names +// ignore_for_file: overridden_fields +// ignore_for_file: unnecessary_cast +// ignore_for_file: unused_element +// ignore_for_file: unused_field +// ignore_for_file: unused_import +// ignore_for_file: unused_local_variable +// ignore_for_file: unused_shown_name + +import "dart:isolate" show ReceivePort; +import "dart:ffi" as ffi; +import "package:jni/internal_helpers_for_jnigen.dart"; +import "package:jni/jni.dart" as jni; + +/// from: com.github.dart_lang.jnigen.SuspendFun +class SuspendFun extends jni.JObject { + @override + late final jni.JObjType $type = type; + + SuspendFun.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = + jni.Jni.findJClass(r"com/github/dart_lang/jnigen/SuspendFun"); + + /// The type which includes information such as the signature of this class. + static const type = $SuspendFunType(); + static final _id_new0 = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"", r"()V"); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory SuspendFun() { + return SuspendFun.fromRef(jni.Jni.accessors + .newObjectWithArgs(_class.reference, _id_new0, []).object); + } + + static final _id_sayHello = jni.Jni.accessors.getMethodIDOf(_class.reference, + r"sayHello", r"(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;"); + + /// from: public final java.lang.Object sayHello(kotlin.coroutines.Continuation continuation) + /// The returned object must be released after use, by calling the [release] method. + Future sayHello() async { + final $p = ReceivePort(); + final $c = + jni.JObject.fromRef(ProtectedJniExtensions.newPortContinuation($p)); + jni.Jni.accessors.callMethodWithArgs(reference, _id_sayHello, + jni.JniCallType.objectType, [$c.reference]).object; + final $o = jni.JObjectPtr.fromAddress(await $p.first); + final $k = const jni.JStringType().getClass().reference; + if (!jni.Jni.env.IsInstanceOf($o, $k)) { + throw "Failed"; + } + return const jni.JStringType().fromRef($o); + } + + static final _id_sayHello1 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"sayHello", + r"(Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;"); + + /// from: public final java.lang.Object sayHello(java.lang.String string, kotlin.coroutines.Continuation continuation) + /// The returned object must be released after use, by calling the [release] method. + Future sayHello1( + jni.JString string, + ) async { + final $p = ReceivePort(); + final $c = + jni.JObject.fromRef(ProtectedJniExtensions.newPortContinuation($p)); + jni.Jni.accessors.callMethodWithArgs(reference, _id_sayHello1, + jni.JniCallType.objectType, [string.reference, $c.reference]).object; + final $o = jni.JObjectPtr.fromAddress(await $p.first); + final $k = const jni.JStringType().getClass().reference; + if (!jni.Jni.env.IsInstanceOf($o, $k)) { + throw "Failed"; + } + return const jni.JStringType().fromRef($o); + } +} + +final class $SuspendFunType extends jni.JObjType { + const $SuspendFunType(); + + @override + String get signature => r"Lcom/github/dart_lang/jnigen/SuspendFun;"; + + @override + SuspendFun fromRef(jni.JObjectPtr ref) => SuspendFun.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($SuspendFunType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($SuspendFunType) && other is $SuspendFunType; + } +} diff --git a/pkgs/jnigen/test/kotlin_test/generate.dart b/pkgs/jnigen/test/kotlin_test/generate.dart new file mode 100644 index 000000000..61686679a --- /dev/null +++ b/pkgs/jnigen/test/kotlin_test/generate.dart @@ -0,0 +1,75 @@ +// 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. + +import 'dart:io'; + +import 'package:logging/logging.dart'; +import 'package:path/path.dart'; +import 'package:jnigen/jnigen.dart'; + +const testName = 'kotlin_test'; +const jarFile = '$testName.jar'; + +final testRoot = join('test', testName); +final kotlinPath = join(testRoot, 'kotlin'); +final jarPath = join(kotlinPath, 'target', jarFile); + +const preamble = ''' +// Copyright (c) 2023, 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. + +'''; + +void compileKotlinSources(String workingDir) async { + final procRes = Process.runSync( + 'mvn', + ['package'], + workingDirectory: workingDir, + runInShell: true, + ); + if (procRes.exitCode != 0) { + throw "mvn exited with ${procRes.exitCode}\n" + "${procRes.stderr}"; + } +} + +Config getConfig([BindingsType bindingsType = BindingsType.cBased]) { + compileKotlinSources(kotlinPath); + final typeDir = bindingsType.getConfigString(); + final cWrapperDir = Uri.directory(join(testRoot, typeDir, "c_bindings")); + final dartWrappersRoot = Uri.directory( + join(testRoot, typeDir, "dart_bindings"), + ); + final config = Config( + classPath: [Uri.file(jarPath)], + classes: [ + // Generating the entire library. + // + // This makes sure that no private class generated by Kotlin can make its + // way to the generated code. + 'com.github.dart_lang.jnigen', + ], + logLevel: Level.ALL, + outputConfig: OutputConfig( + bindingsType: bindingsType, + cConfig: CCodeOutputConfig( + path: cWrapperDir, + libraryName: 'kotlin', + ), + dartConfig: DartCodeOutputConfig( + path: dartWrappersRoot.resolve('kotlin.dart'), + structure: OutputStructure.singleFile, + ), + ), + summarizerOptions: SummarizerOptions(backend: SummarizerBackend.asm), + preamble: preamble, + ); + return config; +} + +void main() async { + await generateJniBindings(getConfig(BindingsType.cBased)); + await generateJniBindings(getConfig(BindingsType.dartOnly)); +} diff --git a/pkgs/jnigen/test/kotlin_test/generated_files_test.dart b/pkgs/jnigen/test/kotlin_test/generated_files_test.dart new file mode 100644 index 000000000..b96c643ca --- /dev/null +++ b/pkgs/jnigen/test/kotlin_test/generated_files_test.dart @@ -0,0 +1,30 @@ +// 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. + +import 'package:jnigen/jnigen.dart'; +import 'package:test/test.dart'; + +import 'generate.dart'; +import '../test_util/test_util.dart'; + +void main() async { + // This is not run in setupAll, because we want to exit with one line of + // error message, not throw a long exception. + await checkLocallyBuiltDependencies(); + generateAndCompareBothModes( + 'Generate and compare bindings for kotlin_test', + getConfig(BindingsType.cBased), + getConfig(BindingsType.dartOnly), + ); + test( + "Generate and analyze bindings for kotlin_test - pure dart", + () async { + await generateAndAnalyzeBindings( + getConfig(BindingsType.dartOnly), + ); + }, + timeout: const Timeout.factor(1.5), + tags: largeTestTag, + ); +} diff --git a/pkgs/jnigen/test/kotlin_test/kotlin/pom.xml b/pkgs/jnigen/test/kotlin_test/kotlin/pom.xml new file mode 100644 index 000000000..b32d4ed1a --- /dev/null +++ b/pkgs/jnigen/test/kotlin_test/kotlin/pom.xml @@ -0,0 +1,119 @@ + + + 4.0.0 + + kotlin + com.github.dart_lang.jnigen + 1.0-SNAPSHOT + jar + consoleApp + + + UTF-8 + official + com.github.dart_lang.jnigen.SuspendFun + 1.8 + + + + + mavenCentral + https://repo1.maven.org/maven2/ + + + + + kotlin_test + src/main/kotlin + src/test/kotlin + + + org.jetbrains.kotlin + kotlin-maven-plugin + 1.7.20 + + + compile + compile + + compile + + + + test-compile + test-compile + + test-compile + + + + + + maven-surefire-plugin + 2.22.2 + + + maven-failsafe-plugin + 2.22.2 + + + org.codehaus.mojo + exec-maven-plugin + 1.6.0 + + MainKt + + + + org.apache.maven.plugins + maven-assembly-plugin + 2.6 + + + make-assembly + package + single + + + + ${main.class} + + + + jar-with-dependencies + + + + + + + + + + + org.jetbrains.kotlin + kotlin-test-junit5 + 1.7.20 + test + + + org.jetbrains.kotlinx + kotlinx-coroutines-core + 1.6.4 + + + org.junit.jupiter + junit-jupiter-engine + 5.8.2 + test + + + org.jetbrains.kotlin + kotlin-stdlib-jdk8 + 1.7.20 + + + + \ No newline at end of file diff --git a/pkgs/jnigen/test/kotlin_test/kotlin/src/main/kotlin/com/github/dart_lang/jnigen/SuspendFun.kt b/pkgs/jnigen/test/kotlin_test/kotlin/src/main/kotlin/com/github/dart_lang/jnigen/SuspendFun.kt new file mode 100644 index 000000000..ffd43769e --- /dev/null +++ b/pkgs/jnigen/test/kotlin_test/kotlin/src/main/kotlin/com/github/dart_lang/jnigen/SuspendFun.kt @@ -0,0 +1,21 @@ +/* Copyright (c) 2023, 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 + +import kotlinx.coroutines.delay +import kotlin.coroutines.Continuation + +public class SuspendFun { + suspend fun sayHello(): String { + delay(100L) + return "Hello!" + } + + suspend fun sayHello(name: String): String { + delay(100L) + return "Hello $name!" + } +} \ No newline at end of file diff --git a/pkgs/jnigen/test/kotlin_test/runtime_test_registrant.dart b/pkgs/jnigen/test/kotlin_test/runtime_test_registrant.dart new file mode 100644 index 000000000..6a9696b6e --- /dev/null +++ b/pkgs/jnigen/test/kotlin_test/runtime_test_registrant.dart @@ -0,0 +1,26 @@ +// Copyright (c) 2023, 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. + +import 'package:test/test.dart'; +import 'package:jni/jni.dart'; + +import '../test_util/callback_types.dart'; + +import 'c_based/dart_bindings/kotlin.dart'; + +void registerTests(String groupName, TestRunnerCallback test) { + group(groupName, () { + test('Suspend functions', () async { + await using((arena) async { + final suspendFun = SuspendFun()..releasedBy(arena); + final hello = await suspendFun.sayHello(); + expect(hello.toDartString(releaseOriginal: true), "Hello!"); + const name = "Bob"; + final helloBob = + await suspendFun.sayHello1(name.toJString()..releasedBy(arena)); + expect(helloBob.toDartString(releaseOriginal: true), "Hello $name!"); + }); + }); + }); +} diff --git a/pkgs/jnigen/test/package_resolver_test.dart b/pkgs/jnigen/test/package_resolver_test.dart new file mode 100644 index 000000000..a29e04362 --- /dev/null +++ b/pkgs/jnigen/test/package_resolver_test.dart @@ -0,0 +1,81 @@ +// 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. + +import 'package:jnigen/src/bindings/resolver.dart'; +import 'package:jnigen/src/elements/elements.dart'; +import 'package:test/test.dart'; + +import 'test_util/test_util.dart'; + +class ResolverTest { + ResolverTest(this.binaryName, this.expectedImport, this.expectedName); + String binaryName; + String expectedImport; + String expectedName; +} + +void main() async { + await checkLocallyBuiltDependencies(); + final resolver = Resolver( + importedClasses: { + 'org.apache.pdfbox.pdmodel.PDDocument': ClassDecl( + declKind: DeclKind.classKind, + binaryName: 'org.apache.pdfbox.pdmodel.PDDocument', + )..path = 'package:pdfbox/pdfbox.dart', + 'android.os.Process': ClassDecl( + declKind: DeclKind.classKind, + binaryName: 'android.os.Process', + )..path = 'package:android/os.dart', + }, + currentClass: 'a.b.N', + inputClassNames: { + 'a.b.C', + 'a.b.c.D', + 'a.b.c.d.E', + 'a.X', + 'e.f.G', + 'e.F', + 'a.g.Y', + 'a.m.n.P' + }, + ); + + final tests = [ + // Absolute imports resolved using import map + ResolverTest('android.os.Process', 'package:android/os.dart', 'process_.'), + ResolverTest('org.apache.pdfbox.pdmodel.PDDocument', + 'package:pdfbox/pdfbox.dart', 'pddocument_.'), + // Relative imports + // inner package + ResolverTest('a.b.c.D', 'c/D.dart', 'd_.'), + // inner package, deeper + ResolverTest('a.b.c.d.E', 'c/d/E.dart', 'e_.'), + // parent package + ResolverTest('a.X', '../X.dart', 'x_.'), + // unrelated package in same translation unit + ResolverTest('e.f.G', '../../e/f/G.dart', 'g_.'), + ResolverTest('e.F', '../../e/F.dart', 'f_.'), + // neighbour package + ResolverTest('a.g.Y', '../g/Y.dart', 'y_.'), + // inner package of a neighbour package + ResolverTest('a.m.n.P', '../m/n/P.dart', 'p_.'), + ]; + + for (var testCase in tests) { + final binaryName = testCase.binaryName; + final packageName = Resolver.getFileClassName(binaryName); + test( + 'getImport $binaryName', + () => expect(resolver.getImport(packageName, binaryName), + equals(testCase.expectedImport))); + test( + 'resolve $binaryName', + () => expect( + resolver.resolvePrefix(ClassDecl( + declKind: DeclKind.classKind, + binaryName: binaryName, + )..path = ''), + equals(testCase.expectedName))); + } +} diff --git a/pkgs/jnigen/test/regenerate_examples_test.dart b/pkgs/jnigen/test/regenerate_examples_test.dart new file mode 100644 index 000000000..35ab2e05b --- /dev/null +++ b/pkgs/jnigen/test/regenerate_examples_test.dart @@ -0,0 +1,74 @@ +// 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. + +import 'dart:io'; + +import 'package:test/test.dart'; +import 'package:path/path.dart' hide equals; + +import 'package:jnigen/jnigen.dart'; +import 'package:jnigen/tools.dart'; + +import 'test_util/test_util.dart'; + +final inAppJava = join('example', 'in_app_java'); +final inAppJavaYaml = join(inAppJava, 'jnigen.yaml'); +final notificationPlugin = join('example', 'notification_plugin'); +final notificationPluginYaml = join(notificationPlugin, 'jnigen.yaml'); +final kotlinPlugin = join('example', 'kotlin_plugin'); +final kotlinPluginYaml = join(kotlinPlugin, 'jnigen.yaml'); + +/// Generates bindings using jnigen config in [exampleName] and compares +/// them to provided reference outputs. +/// +/// [dartOutput] and [cOutput] are relative paths from example project dir. +/// +/// Pass [isLargeTest] as true if the test will take considerable time. +void testExample(String exampleName, String dartOutput, String? cOutput, + {bool isLargeTest = false}) { + test( + 'Generate and compare bindings for $exampleName', + timeout: const Timeout.factor(3), + () async { + final examplePath = join('example', exampleName); + final configPath = join(examplePath, 'jnigen.yaml'); + + final config = Config.parseArgs(['--config', configPath]); + try { + await generateAndCompareBindings(config); + } on GradleException catch (_) { + stderr.writeln('Skip: $exampleName'); + } + }, + tags: isLargeTest ? largeTestTag : null, + ); +} + +void main() async { + await checkLocallyBuiltDependencies(); + testExample( + 'in_app_java', + join('lib', 'android_utils.dart'), + join('src', 'android_utils'), + isLargeTest: true, + ); + testExample( + 'pdfbox_plugin', + join('lib', 'src', 'third_party'), + 'src', + isLargeTest: false, + ); + testExample( + 'notification_plugin', + join('lib', 'notifications.dart'), + 'src', + isLargeTest: true, + ); + testExample( + 'kotlin_plugin', + join('lib', 'kotlin_bindings.dart'), + 'src', + isLargeTest: true, + ); +} diff --git a/pkgs/jnigen/test/simple_package_test/.gitignore b/pkgs/jnigen/test/simple_package_test/.gitignore new file mode 100644 index 000000000..1db9cf8ee --- /dev/null +++ b/pkgs/jnigen/test/simple_package_test/.gitignore @@ -0,0 +1,6 @@ +build/ +*.class +test_lib/ +test_src/ +*_dartonly_generated.dart ## Generated test replicas +generated_runtime_test.dart \ No newline at end of file diff --git a/pkgs/jnigen/test/simple_package_test/c_based/c_bindings/.clang-format b/pkgs/jnigen/test/simple_package_test/c_based/c_bindings/.clang-format new file mode 100644 index 000000000..a256c2f09 --- /dev/null +++ b/pkgs/jnigen/test/simple_package_test/c_based/c_bindings/.clang-format @@ -0,0 +1,15 @@ +# From dart SDK: https://github.com/dart-lang/sdk/blob/main/.clang-format + +# Defines the Chromium style for automatic reformatting. +# http://clang.llvm.org/docs/ClangFormatStyleOptions.html +BasedOnStyle: Chromium + +# clang-format doesn't seem to do a good job of this for longer comments. +ReflowComments: 'false' + +# We have lots of these. Though we need to put them all in curly braces, +# clang-format can't do that. +AllowShortIfStatementsOnASingleLine: 'true' + +# Put escaped newlines into the rightmost column. +AlignEscapedNewlinesLeft: false diff --git a/pkgs/jnigen/test/simple_package_test/c_based/c_bindings/CMakeLists.txt b/pkgs/jnigen/test/simple_package_test/c_based/c_bindings/CMakeLists.txt new file mode 100644 index 000000000..eeb352dc0 --- /dev/null +++ b/pkgs/jnigen/test/simple_package_test/c_based/c_bindings/CMakeLists.txt @@ -0,0 +1,32 @@ +# jni_native_build (Build with jni:setup. Do not delete this line.) + +# The Flutter tooling requires that developers have CMake 3.10 or later +# installed. You should not increase this version, as doing so will cause +# the plugin to fail to compile for some customers of the plugin. +cmake_minimum_required(VERSION 3.10) + +project(simple_package VERSION 0.0.1 LANGUAGES C) + +add_library(simple_package SHARED + "./simple_package.c" +) + +set_target_properties(simple_package PROPERTIES + OUTPUT_NAME "simple_package" +) + +target_compile_definitions(simple_package PUBLIC DART_SHARED_LIB) + +if(WIN32) + set_target_properties(${TARGET_NAME} PROPERTIES + LINK_FLAGS "/DELAYLOAD:jvm.dll") +endif() + +if (ANDROID) + target_link_libraries(simple_package log) +else() + find_package(Java REQUIRED) + find_package(JNI REQUIRED) + include_directories(${JNI_INCLUDE_DIRS}) + target_link_libraries(simple_package ${JNI_LIBRARIES}) +endif() diff --git a/pkgs/jnigen/test/simple_package_test/c_based/c_bindings/dartjni.h b/pkgs/jnigen/test/simple_package_test/c_based/c_bindings/dartjni.h new file mode 100644 index 000000000..8f1dc7481 --- /dev/null +++ b/pkgs/jnigen/test/simple_package_test/c_based/c_bindings/dartjni.h @@ -0,0 +1,424 @@ +// 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. + +#pragma once + +// Note: include appropriate system jni.h as found by CMake, not third_party/jni.h. +#include +#include +#include +#include + +#if _WIN32 +#include +#else +#include +#include +#endif + +#if _WIN32 +#define FFI_PLUGIN_EXPORT __declspec(dllexport) +#else +#define FFI_PLUGIN_EXPORT +#endif + +#if defined _WIN32 +#define thread_local __declspec(thread) +#else +#define thread_local __thread +#endif + +#ifdef __ANDROID__ +#include +#endif + +#ifdef __ANDROID__ +#define __ENVP_CAST (JNIEnv**) +#else +#define __ENVP_CAST (void**) +#endif + +/// Locking functions for windows and pthread. + +#if defined _WIN32 +#include + +typedef CRITICAL_SECTION MutexLock; +typedef CONDITION_VARIABLE ConditionVariable; + +static inline void init_lock(MutexLock* lock) { + InitializeCriticalSection(lock); +} + +static inline void acquire_lock(MutexLock* lock) { + EnterCriticalSection(lock); +} + +static inline void release_lock(MutexLock* lock) { + LeaveCriticalSection(lock); +} + +static inline void destroy_lock(MutexLock* lock) { + DeleteCriticalSection(lock); +} + +static inline void init_cond(ConditionVariable* cond) { + InitializeConditionVariable(cond); +} + +static inline void signal_cond(ConditionVariable* cond) { + WakeConditionVariable(cond); +} + +static inline void wait_for(ConditionVariable* cond, MutexLock* lock) { + SleepConditionVariableCS(cond, lock, INFINITE); +} + +static inline void destroy_cond(ConditionVariable* cond) { + // Not available. +} + +#elif defined __APPLE__ || defined __LINUX__ || defined __ANDROID__ || \ + defined __GNUC__ +#include + +typedef pthread_mutex_t MutexLock; +typedef pthread_cond_t ConditionVariable; + +static inline void init_lock(MutexLock* lock) { + pthread_mutex_init(lock, NULL); +} + +static inline void acquire_lock(MutexLock* lock) { + pthread_mutex_lock(lock); +} + +static inline void release_lock(MutexLock* lock) { + pthread_mutex_unlock(lock); +} + +static inline void destroy_lock(MutexLock* lock) { + pthread_mutex_destroy(lock); +} + +static inline void init_cond(ConditionVariable* cond) { + pthread_cond_init(cond, NULL); +} + +static inline void signal_cond(ConditionVariable* cond) { + pthread_cond_signal(cond); +} + +static inline void wait_for(ConditionVariable* cond, MutexLock* lock) { + pthread_cond_wait(cond, lock); +} + +static inline void destroy_cond(ConditionVariable* cond) { + pthread_cond_destroy(cond); +} + +#else + +#error "No locking/condition variable support; Possibly unsupported platform" + +#endif + +typedef struct CallbackResult { + MutexLock lock; + ConditionVariable cond; + int ready; + jobject object; +} CallbackResult; + +typedef struct JniLocks { + MutexLock classLoadingLock; + MutexLock methodLoadingLock; + MutexLock fieldLoadingLock; +} JniLocks; + +/// Represents the error when dart-jni layer has already spawned singleton VM. +#define DART_JNI_SINGLETON_EXISTS (-99); + +/// Stores the global state of the JNI. +typedef struct JniContext { + JavaVM* jvm; + jobject classLoader; + jmethodID loadClassMethod; + jobject currentActivity; + jobject appContext; + JniLocks locks; +} JniContext; + +// jniEnv for this thread, used by inline functions in this header, +// therefore declared as extern. +extern thread_local JNIEnv* jniEnv; + +extern JniContext* jni; + +/// Types used by JNI API to distinguish between primitive types. +enum JniType { + booleanType = 0, + byteType = 1, + shortType = 2, + charType = 3, + intType = 4, + longType = 5, + floatType = 6, + doubleType = 7, + objectType = 8, + voidType = 9, +}; + +/// Result type for use by JNI. +/// +/// If [exception] is null, it means the result is valid. +/// It's assumed that the caller knows the expected type in [result]. +typedef struct JniResult { + jvalue value; + jthrowable exception; +} JniResult; + +/// Similar to [JniResult] but for class lookups. +typedef struct JniClassLookupResult { + jclass value; + jthrowable exception; +} JniClassLookupResult; + +/// Similar to [JniResult] but for method/field ID lookups. +typedef struct JniPointerResult { + const void* value; + jthrowable exception; +} JniPointerResult; + +/// JniExceptionDetails holds 2 jstring objects, one is the result of +/// calling `toString` on exception object, other is stack trace; +typedef struct JniExceptionDetails { + jstring message; + jstring stacktrace; +} JniExceptionDetails; + +/// This struct contains functions which wrap method call / field access conveniently along with +/// exception checking. +/// +/// Flutter embedding checks for pending JNI exceptions before an FFI transition, which requires us +/// to check for and clear the exception before returning to dart code, which requires these functions +/// to return result types. +typedef struct JniAccessorsStruct { + JniClassLookupResult (*getClass)(char* internalName); + JniPointerResult (*getFieldID)(jclass cls, char* fieldName, char* signature); + JniPointerResult (*getStaticFieldID)(jclass cls, + char* fieldName, + char* signature); + JniPointerResult (*getMethodID)(jclass cls, + char* methodName, + char* signature); + JniPointerResult (*getStaticMethodID)(jclass cls, + char* methodName, + char* signature); + JniResult (*newObject)(jclass cls, jmethodID ctor, jvalue* args); + JniResult (*newPrimitiveArray)(jsize length, int type); + JniResult (*newObjectArray)(jsize length, + jclass elementClass, + jobject initialElement); + JniResult (*getArrayElement)(jarray array, int index, int type); + JniResult (*callMethod)(jobject obj, + jmethodID methodID, + int callType, + jvalue* args); + JniResult (*callStaticMethod)(jclass cls, + jmethodID methodID, + int callType, + jvalue* args); + JniResult (*getField)(jobject obj, jfieldID fieldID, int callType); + JniResult (*getStaticField)(jclass cls, jfieldID fieldID, int callType); + JniExceptionDetails (*getExceptionDetails)(jthrowable exception); +} JniAccessorsStruct; + +FFI_PLUGIN_EXPORT JniAccessorsStruct* GetAccessors(); + +FFI_PLUGIN_EXPORT JavaVM* GetJavaVM(void); + +FFI_PLUGIN_EXPORT JNIEnv* GetJniEnv(void); + +/// Spawn a JVM with given arguments. +/// +/// Returns JNI_OK on success, and one of the documented JNI error codes on +/// failure. It returns DART_JNI_SINGLETON_EXISTS if an attempt to spawn multiple +/// JVMs is made, even if the underlying API potentially supports multiple VMs. +FFI_PLUGIN_EXPORT int SpawnJvm(JavaVMInitArgs* args); + +/// Load class through platform-specific mechanism. +/// +/// Currently uses application classloader on android, +/// and JNIEnv->FindClass on other platforms. +FFI_PLUGIN_EXPORT jclass FindClass(const char* name); + +/// Returns Application classLoader (on Android), +/// which can be used to load application and platform classes. +/// +/// On other platforms, NULL is returned. +FFI_PLUGIN_EXPORT jobject GetClassLoader(void); + +/// Returns application context on Android. +/// +/// On other platforms, NULL is returned. +FFI_PLUGIN_EXPORT jobject GetApplicationContext(void); + +/// Returns current activity of the app on Android. +FFI_PLUGIN_EXPORT jobject GetCurrentActivity(void); + +static inline void attach_thread() { + if (jniEnv == NULL) { + (*jni->jvm)->AttachCurrentThread(jni->jvm, __ENVP_CAST & jniEnv, NULL); + } +} + +/// Load class into [cls] using platform specific mechanism +static inline void load_class_platform(jclass* cls, const char* name) { +#ifdef __ANDROID__ + jstring className = (*jniEnv)->NewStringUTF(jniEnv, name); + *cls = (*jniEnv)->CallObjectMethod(jniEnv, jni->classLoader, + jni->loadClassMethod, className); + (*jniEnv)->DeleteLocalRef(jniEnv, className); +#else + *cls = (*jniEnv)->FindClass(jniEnv, name); +#endif +} + +static inline void load_class_local_ref(jclass* cls, const char* name) { + if (*cls == NULL) { + acquire_lock(&jni->locks.classLoadingLock); + if (*cls == NULL) { + load_class_platform(cls, name); + } + release_lock(&jni->locks.classLoadingLock); + } +} + +static inline void load_class_global_ref(jclass* cls, const char* name) { + if (*cls == NULL) { + jclass tmp = NULL; + acquire_lock(&jni->locks.classLoadingLock); + if (*cls == NULL) { + load_class_platform(&tmp, name); + if (!(*jniEnv)->ExceptionCheck(jniEnv)) { + *cls = (*jniEnv)->NewGlobalRef(jniEnv, tmp); + (*jniEnv)->DeleteLocalRef(jniEnv, tmp); + } + } + release_lock(&jni->locks.classLoadingLock); + } +} + +static inline void load_method(jclass cls, + jmethodID* res, + const char* name, + const char* sig) { + if (*res == NULL) { + acquire_lock(&jni->locks.methodLoadingLock); + if (*res == NULL) { + *res = (*jniEnv)->GetMethodID(jniEnv, cls, name, sig); + } + release_lock(&jni->locks.methodLoadingLock); + } +} + +static inline void load_static_method(jclass cls, + jmethodID* res, + const char* name, + const char* sig) { + if (*res == NULL) { + acquire_lock(&jni->locks.methodLoadingLock); + if (*res == NULL) { + *res = (*jniEnv)->GetStaticMethodID(jniEnv, cls, name, sig); + } + release_lock(&jni->locks.methodLoadingLock); + } +} + +static inline void load_field(jclass cls, + jfieldID* res, + const char* name, + const char* sig) { + if (*res == NULL) { + acquire_lock(&jni->locks.fieldLoadingLock); + if (*res == NULL) { + *res = (*jniEnv)->GetFieldID(jniEnv, cls, name, sig); + } + release_lock(&jni->locks.fieldLoadingLock); + } +} + +static inline void load_static_field(jclass cls, + jfieldID* res, + const char* name, + const char* sig) { + if (*res == NULL) { + acquire_lock(&jni->locks.fieldLoadingLock); + if (*res == NULL) { + *res = (*jniEnv)->GetStaticFieldID(jniEnv, cls, name, sig); + } + release_lock(&jni->locks.fieldLoadingLock); + } +} + +static inline jobject to_global_ref(jobject ref) { + jobject g = (*jniEnv)->NewGlobalRef(jniEnv, ref); + (*jniEnv)->DeleteLocalRef(jniEnv, ref); + return g; +} + +// These functions are useful for C+Dart bindings, and not required for pure dart bindings. + +FFI_PLUGIN_EXPORT JniContext* GetJniContextPtr(); + +/// For use by jni_gen's generated code +/// don't use these. + +// these 2 fn ptr vars will be defined by generated code library +extern JniContext* (*context_getter)(void); +extern JNIEnv* (*env_getter)(void); + +// this function will be exported by generated code library +// it will set above 2 variables. +FFI_PLUGIN_EXPORT void setJniGetters(struct JniContext* (*cg)(void), + JNIEnv* (*eg)(void)); + +static inline void load_env() { + if (jniEnv == NULL) { + jni = context_getter(); + jniEnv = env_getter(); + } +} + +static inline jthrowable check_exception() { + jthrowable exception = (*jniEnv)->ExceptionOccurred(jniEnv); + if (exception != NULL) (*jniEnv)->ExceptionClear(jniEnv); + if (exception == NULL) return NULL; + return to_global_ref(exception); +} + +static inline JniResult to_global_ref_result(jobject ref) { + JniResult result; + result.exception = check_exception(); + if (result.exception == NULL) { + result.value.l = to_global_ref(ref); + } + return result; +} + +FFI_PLUGIN_EXPORT intptr_t InitDartApiDL(void* data); + +FFI_PLUGIN_EXPORT +JniResult DartException__ctor(jstring message); + +FFI_PLUGIN_EXPORT +JniResult PortContinuation__ctor(int64_t j); + +FFI_PLUGIN_EXPORT +JniResult PortProxy__newInstance(jobject binaryName, + int64_t port, + int64_t functionPtr); + +FFI_PLUGIN_EXPORT void resultFor(CallbackResult* result, jobject object); diff --git a/pkgs/jnigen/test/simple_package_test/c_based/c_bindings/simple_package.c b/pkgs/jnigen/test/simple_package_test/c_based/c_bindings/simple_package.c new file mode 100644 index 000000000..20c7e7e53 --- /dev/null +++ b/pkgs/jnigen/test/simple_package_test/c_based/c_bindings/simple_package.c @@ -0,0 +1,2954 @@ +// 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. + +// Autogenerated by jnigen. DO NOT EDIT! + +#include +#include "dartjni.h" +#include "jni.h" + +thread_local JNIEnv* jniEnv; +JniContext* jni; + +JniContext* (*context_getter)(void); +JNIEnv* (*env_getter)(void); + +void setJniGetters(JniContext* (*cg)(void), JNIEnv* (*eg)(void)) { + context_getter = cg; + env_getter = eg; +} + +// com.github.dart_lang.jnigen.simple_package.Color +jclass _c_Color = NULL; + +jmethodID _m_Color__values = NULL; +FFI_PLUGIN_EXPORT +JniResult Color__values() { + load_env(); + load_class_global_ref(&_c_Color, + "com/github/dart_lang/jnigen/simple_package/Color"); + if (_c_Color == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_Color, &_m_Color__values, "values", + "()[Lcom/github/dart_lang/jnigen/simple_package/Color;"); + if (_m_Color__values == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallStaticObjectMethod(jniEnv, _c_Color, _m_Color__values); + return to_global_ref_result(_result); +} + +jmethodID _m_Color__valueOf = NULL; +FFI_PLUGIN_EXPORT +JniResult Color__valueOf(jobject name) { + load_env(); + load_class_global_ref(&_c_Color, + "com/github/dart_lang/jnigen/simple_package/Color"); + if (_c_Color == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method( + _c_Color, &_m_Color__valueOf, "valueOf", + "(Ljava/lang/String;)Lcom/github/dart_lang/jnigen/simple_package/Color;"); + if (_m_Color__valueOf == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod(jniEnv, _c_Color, + _m_Color__valueOf, name); + return to_global_ref_result(_result); +} + +// com.github.dart_lang.jnigen.simple_package.Example +jclass _c_Example = NULL; + +jmethodID _m_Example__getAmount = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__getAmount() { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_Example, &_m_Example__getAmount, "getAmount", "()I"); + if (_m_Example__getAmount == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = + (*jniEnv)->CallStaticIntMethod(jniEnv, _c_Example, _m_Example__getAmount); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_Example__getPi = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__getPi() { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_Example, &_m_Example__getPi, "getPi", "()D"); + if (_m_Example__getPi == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + double _result = + (*jniEnv)->CallStaticDoubleMethod(jniEnv, _c_Example, _m_Example__getPi); + return (JniResult){.value = {.d = _result}, .exception = check_exception()}; +} + +jmethodID _m_Example__getAsterisk = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__getAsterisk() { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_Example, &_m_Example__getAsterisk, "getAsterisk", + "()C"); + if (_m_Example__getAsterisk == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint16_t _result = (*jniEnv)->CallStaticCharMethod(jniEnv, _c_Example, + _m_Example__getAsterisk); + return (JniResult){.value = {.c = _result}, .exception = check_exception()}; +} + +jmethodID _m_Example__getName = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__getName() { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_Example, &_m_Example__getName, "getName", + "()Ljava/lang/String;"); + if (_m_Example__getName == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod(jniEnv, _c_Example, + _m_Example__getName); + return to_global_ref_result(_result); +} + +jmethodID _m_Example__getNestedInstance = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__getNestedInstance() { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method( + _c_Example, &_m_Example__getNestedInstance, "getNestedInstance", + "()Lcom/github/dart_lang/jnigen/simple_package/Example$Nested;"); + if (_m_Example__getNestedInstance == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_Example, _m_Example__getNestedInstance); + return to_global_ref_result(_result); +} + +jmethodID _m_Example__setAmount = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__setAmount(int32_t newAmount) { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_Example, &_m_Example__setAmount, "setAmount", "(I)V"); + if (_m_Example__setAmount == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallStaticVoidMethod(jniEnv, _c_Example, _m_Example__setAmount, + newAmount); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_Example__setName = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__setName(jobject newName) { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_Example, &_m_Example__setName, "setName", + "(Ljava/lang/String;)V"); + if (_m_Example__setName == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallStaticVoidMethod(jniEnv, _c_Example, _m_Example__setName, + newName); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_Example__setNestedInstance = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__setNestedInstance(jobject newNested) { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method( + _c_Example, &_m_Example__setNestedInstance, "setNestedInstance", + "(Lcom/github/dart_lang/jnigen/simple_package/Example$Nested;)V"); + if (_m_Example__setNestedInstance == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallStaticVoidMethod(jniEnv, _c_Example, + _m_Example__setNestedInstance, newNested); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_Example__max4 = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__max4(int32_t a, int32_t b, int32_t c, int32_t d) { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_Example, &_m_Example__max4, "max4", "(IIII)I"); + if (_m_Example__max4 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = (*jniEnv)->CallStaticIntMethod( + jniEnv, _c_Example, _m_Example__max4, a, b, c, d); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_Example__max8 = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__max8(int32_t a, + int32_t b, + int32_t c, + int32_t d, + int32_t e, + int32_t f, + int32_t g, + int32_t h) { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_Example, &_m_Example__max8, "max8", "(IIIIIIII)I"); + if (_m_Example__max8 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = (*jniEnv)->CallStaticIntMethod( + jniEnv, _c_Example, _m_Example__max8, a, b, c, d, e, f, g, h); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_Example__getNumber = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__getNumber(jobject self_) { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example, &_m_Example__getNumber, "getNumber", "()I"); + if (_m_Example__getNumber == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = + (*jniEnv)->CallIntMethod(jniEnv, self_, _m_Example__getNumber); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_Example__setNumber = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__setNumber(jobject self_, int32_t number) { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example, &_m_Example__setNumber, "setNumber", "(I)V"); + if (_m_Example__setNumber == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_Example__setNumber, number); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_Example__getIsUp = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__getIsUp(jobject self_) { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example, &_m_Example__getIsUp, "getIsUp", "()Z"); + if (_m_Example__getIsUp == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = + (*jniEnv)->CallBooleanMethod(jniEnv, self_, _m_Example__getIsUp); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_Example__setUp = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__setUp(jobject self_, uint8_t isUp) { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example, &_m_Example__setUp, "setUp", "(Z)V"); + if (_m_Example__setUp == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_Example__setUp, isUp); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_Example__getCodename = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__getCodename(jobject self_) { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example, &_m_Example__getCodename, "getCodename", + "()Ljava/lang/String;"); + if (_m_Example__getCodename == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_Example__getCodename); + return to_global_ref_result(_result); +} + +jmethodID _m_Example__setCodename = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__setCodename(jobject self_, jobject codename) { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example, &_m_Example__setCodename, "setCodename", + "(Ljava/lang/String;)V"); + if (_m_Example__setCodename == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_Example__setCodename, codename); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_Example__getRandom = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__getRandom(jobject self_) { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example, &_m_Example__getRandom, "getRandom", + "()Ljava/util/Random;"); + if (_m_Example__getRandom == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_Example__getRandom); + return to_global_ref_result(_result); +} + +jmethodID _m_Example__setRandom = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__setRandom(jobject self_, jobject random) { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example, &_m_Example__setRandom, "setRandom", + "(Ljava/util/Random;)V"); + if (_m_Example__setRandom == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_Example__setRandom, random); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_Example__getRandomLong = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__getRandomLong(jobject self_) { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example, &_m_Example__getRandomLong, "getRandomLong", "()J"); + if (_m_Example__getRandomLong == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int64_t _result = + (*jniEnv)->CallLongMethod(jniEnv, self_, _m_Example__getRandomLong); + return (JniResult){.value = {.j = _result}, .exception = check_exception()}; +} + +jmethodID _m_Example__add4Longs = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__add4Longs(jobject self_, + int64_t a, + int64_t b, + int64_t c, + int64_t d) { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example, &_m_Example__add4Longs, "add4Longs", "(JJJJ)J"); + if (_m_Example__add4Longs == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int64_t _result = (*jniEnv)->CallLongMethod( + jniEnv, self_, _m_Example__add4Longs, a, b, c, d); + return (JniResult){.value = {.j = _result}, .exception = check_exception()}; +} + +jmethodID _m_Example__add8Longs = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__add8Longs(jobject self_, + int64_t a, + int64_t b, + int64_t c, + int64_t d, + int64_t e, + int64_t f, + int64_t g, + int64_t h) { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example, &_m_Example__add8Longs, "add8Longs", "(JJJJJJJJ)J"); + if (_m_Example__add8Longs == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int64_t _result = (*jniEnv)->CallLongMethod( + jniEnv, self_, _m_Example__add8Longs, a, b, c, d, e, f, g, h); + return (JniResult){.value = {.j = _result}, .exception = check_exception()}; +} + +jmethodID _m_Example__getRandomNumericString = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__getRandomNumericString(jobject self_, jobject random) { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example, &_m_Example__getRandomNumericString, + "getRandomNumericString", + "(Ljava/util/Random;)Ljava/lang/String;"); + if (_m_Example__getRandomNumericString == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_Example__getRandomNumericString, random); + return to_global_ref_result(_result); +} + +jmethodID _m_Example__protectedMethod = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__protectedMethod(jobject self_, jobject a, jobject b) { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example, &_m_Example__protectedMethod, "protectedMethod", + "(Ljava/lang/String;Ljava/lang/String;)V"); + if (_m_Example__protectedMethod == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_Example__protectedMethod, a, b); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_Example__finalMethod = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__finalMethod(jobject self_) { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example, &_m_Example__finalMethod, "finalMethod", "()V"); + if (_m_Example__finalMethod == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_Example__finalMethod); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_Example__getList = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__getList(jobject self_) { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example, &_m_Example__getList, "getList", + "()Ljava/util/List;"); + if (_m_Example__getList == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_Example__getList); + return to_global_ref_result(_result); +} + +jmethodID _m_Example__joinStrings = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__joinStrings(jobject self_, jobject values, jobject delim) { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example, &_m_Example__joinStrings, "joinStrings", + "(Ljava/util/List;Ljava/lang/String;)Ljava/lang/String;"); + if (_m_Example__joinStrings == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_Example__joinStrings, values, delim); + return to_global_ref_result(_result); +} + +jmethodID _m_Example__methodWithSeveralParams = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__methodWithSeveralParams(jobject self_, + uint16_t ch, + jobject s, + jobject a, + jobject t, + jobject lt, + jobject wm) { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example, &_m_Example__methodWithSeveralParams, + "methodWithSeveralParams", + "(CLjava/lang/String;[ILjava/lang/CharSequence;Ljava/util/" + "List;Ljava/util/Map;)V"); + if (_m_Example__methodWithSeveralParams == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_Example__methodWithSeveralParams, + ch, s, a, t, lt, wm); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_Example__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__new0() { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example, &_m_Example__new0, "", "()V"); + if (_m_Example__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject(jniEnv, _c_Example, _m_Example__new0); + return to_global_ref_result(_result); +} + +jmethodID _m_Example__new1 = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__new1(int32_t number) { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example, &_m_Example__new1, "", "(I)V"); + if (_m_Example__new1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->NewObject(jniEnv, _c_Example, _m_Example__new1, number); + return to_global_ref_result(_result); +} + +jmethodID _m_Example__new2 = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__new2(int32_t number, uint8_t isUp) { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example, &_m_Example__new2, "", "(IZ)V"); + if (_m_Example__new2 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->NewObject(jniEnv, _c_Example, _m_Example__new2, number, isUp); + return to_global_ref_result(_result); +} + +jmethodID _m_Example__new3 = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__new3(int32_t number, uint8_t isUp, jobject codename) { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example, &_m_Example__new3, "", + "(IZLjava/lang/String;)V"); + if (_m_Example__new3 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject(jniEnv, _c_Example, _m_Example__new3, + number, isUp, codename); + return to_global_ref_result(_result); +} + +jmethodID _m_Example__new4 = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__new4(int32_t a, + int32_t b, + int32_t c, + int32_t d, + int32_t e, + int32_t f, + int32_t g, + int32_t h) { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example, &_m_Example__new4, "", "(IIIIIIII)V"); + if (_m_Example__new4 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject(jniEnv, _c_Example, _m_Example__new4, + a, b, c, d, e, f, g, h); + return to_global_ref_result(_result); +} + +jmethodID _m_Example__whichExample = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__whichExample(jobject self_) { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example, &_m_Example__whichExample, "whichExample", "()I"); + if (_m_Example__whichExample == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = + (*jniEnv)->CallIntMethod(jniEnv, self_, _m_Example__whichExample); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_Example__addInts = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__addInts(int32_t a, int32_t b) { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_Example, &_m_Example__addInts, "addInts", "(II)I"); + if (_m_Example__addInts == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = (*jniEnv)->CallStaticIntMethod(jniEnv, _c_Example, + _m_Example__addInts, a, b); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_Example__getArr = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__getArr() { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_Example, &_m_Example__getArr, "getArr", "()[I"); + if (_m_Example__getArr == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallStaticObjectMethod(jniEnv, _c_Example, _m_Example__getArr); + return to_global_ref_result(_result); +} + +jmethodID _m_Example__addAll = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__addAll(jobject arr) { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_Example, &_m_Example__addAll, "addAll", "([I)I"); + if (_m_Example__addAll == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = (*jniEnv)->CallStaticIntMethod(jniEnv, _c_Example, + _m_Example__addAll, arr); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_Example__getSelf = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__getSelf(jobject self_) { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example, &_m_Example__getSelf, "getSelf", + "()Lcom/github/dart_lang/jnigen/simple_package/Example;"); + if (_m_Example__getSelf == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_Example__getSelf); + return to_global_ref_result(_result); +} + +jmethodID _m_Example__throwException = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__throwException() { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_Example, &_m_Example__throwException, "throwException", + "()V"); + if (_m_Example__throwException == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallStaticVoidMethod(jniEnv, _c_Example, + _m_Example__throwException); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_Example__overloaded = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__overloaded(jobject self_) { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example, &_m_Example__overloaded, "overloaded", "()V"); + if (_m_Example__overloaded == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_Example__overloaded); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_Example__overloaded1 = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__overloaded1(jobject self_, int32_t a, jobject b) { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example, &_m_Example__overloaded1, "overloaded", + "(ILjava/lang/String;)V"); + if (_m_Example__overloaded1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_Example__overloaded1, a, b); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_Example__overloaded2 = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__overloaded2(jobject self_, int32_t a) { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example, &_m_Example__overloaded2, "overloaded", "(I)V"); + if (_m_Example__overloaded2 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_Example__overloaded2, a); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_Example__overloaded3 = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__overloaded3(jobject self_, jobject a, jobject b) { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example, &_m_Example__overloaded3, "overloaded", + "(Ljava/util/List;Ljava/lang/String;)V"); + if (_m_Example__overloaded3 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_Example__overloaded3, a, b); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_Example__overloaded4 = NULL; +FFI_PLUGIN_EXPORT +JniResult Example__overloaded4(jobject self_, jobject a) { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example, &_m_Example__overloaded4, "overloaded", + "(Ljava/util/List;)V"); + if (_m_Example__overloaded4 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_Example__overloaded4, a); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jfieldID _f_Example__unusedRandom = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Example__unusedRandom() { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Example, &_f_Example__unusedRandom, "unusedRandom", + "Ljava/util/Random;"); + jobject _result = (*jniEnv)->GetStaticObjectField(jniEnv, _c_Example, + _f_Example__unusedRandom); + return to_global_ref_result(_result); +} + +jfieldID _f_Example__protectedField = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Example__protectedField(jobject self_) { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_Example, &_f_Example__protectedField, "protectedField", + "Ljava/util/Random;"); + jobject _result = + (*jniEnv)->GetObjectField(jniEnv, self_, _f_Example__protectedField); + return to_global_ref_result(_result); +} + +FFI_PLUGIN_EXPORT +JniResult set_Example__protectedField(jobject self_, jobject value) { + load_env(); + load_class_global_ref(&_c_Example, + "com/github/dart_lang/jnigen/simple_package/Example"); + if (_c_Example == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_Example, &_f_Example__protectedField, "protectedField", + "Ljava/util/Random;"); + (*jniEnv)->SetObjectField(jniEnv, self_, _f_Example__protectedField, value); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +// com.github.dart_lang.jnigen.simple_package.Example$Nested +jclass _c_Example_Nested = NULL; + +jmethodID _m_Example_Nested__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult Example_Nested__new0(uint8_t value) { + load_env(); + load_class_global_ref( + &_c_Example_Nested, + "com/github/dart_lang/jnigen/simple_package/Example$Nested"); + if (_c_Example_Nested == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example_Nested, &_m_Example_Nested__new0, "", "(Z)V"); + if (_m_Example_Nested__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject(jniEnv, _c_Example_Nested, + _m_Example_Nested__new0, value); + return to_global_ref_result(_result); +} + +jmethodID _m_Example_Nested__usesAnonymousInnerClass = NULL; +FFI_PLUGIN_EXPORT +JniResult Example_Nested__usesAnonymousInnerClass(jobject self_) { + load_env(); + load_class_global_ref( + &_c_Example_Nested, + "com/github/dart_lang/jnigen/simple_package/Example$Nested"); + if (_c_Example_Nested == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example_Nested, &_m_Example_Nested__usesAnonymousInnerClass, + "usesAnonymousInnerClass", "()V"); + if (_m_Example_Nested__usesAnonymousInnerClass == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, + _m_Example_Nested__usesAnonymousInnerClass); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_Example_Nested__getValue = NULL; +FFI_PLUGIN_EXPORT +JniResult Example_Nested__getValue(jobject self_) { + load_env(); + load_class_global_ref( + &_c_Example_Nested, + "com/github/dart_lang/jnigen/simple_package/Example$Nested"); + if (_c_Example_Nested == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example_Nested, &_m_Example_Nested__getValue, "getValue", + "()Z"); + if (_m_Example_Nested__getValue == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + uint8_t _result = + (*jniEnv)->CallBooleanMethod(jniEnv, self_, _m_Example_Nested__getValue); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +jmethodID _m_Example_Nested__setValue = NULL; +FFI_PLUGIN_EXPORT +JniResult Example_Nested__setValue(jobject self_, uint8_t value) { + load_env(); + load_class_global_ref( + &_c_Example_Nested, + "com/github/dart_lang/jnigen/simple_package/Example$Nested"); + if (_c_Example_Nested == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example_Nested, &_m_Example_Nested__setValue, "setValue", + "(Z)V"); + if (_m_Example_Nested__setValue == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_Example_Nested__setValue, value); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +// com.github.dart_lang.jnigen.simple_package.Example$Nested$NestedTwice +jclass _c_Example_Nested_NestedTwice = NULL; + +jmethodID _m_Example_Nested_NestedTwice__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult Example_Nested_NestedTwice__new0() { + load_env(); + load_class_global_ref( + &_c_Example_Nested_NestedTwice, + "com/github/dart_lang/jnigen/simple_package/Example$Nested$NestedTwice"); + if (_c_Example_Nested_NestedTwice == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example_Nested_NestedTwice, + &_m_Example_Nested_NestedTwice__new0, "", "()V"); + if (_m_Example_Nested_NestedTwice__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject(jniEnv, _c_Example_Nested_NestedTwice, + _m_Example_Nested_NestedTwice__new0); + return to_global_ref_result(_result); +} + +jfieldID _f_Example_Nested_NestedTwice__ZERO = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Example_Nested_NestedTwice__ZERO() { + load_env(); + load_class_global_ref( + &_c_Example_Nested_NestedTwice, + "com/github/dart_lang/jnigen/simple_package/Example$Nested$NestedTwice"); + if (_c_Example_Nested_NestedTwice == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Example_Nested_NestedTwice, + &_f_Example_Nested_NestedTwice__ZERO, "ZERO", "I"); + int32_t _result = + (*jniEnv)->GetStaticIntField(jniEnv, _c_Example_Nested_NestedTwice, + _f_Example_Nested_NestedTwice__ZERO); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +FFI_PLUGIN_EXPORT +JniResult set_Example_Nested_NestedTwice__ZERO(int32_t value) { + load_env(); + load_class_global_ref( + &_c_Example_Nested_NestedTwice, + "com/github/dart_lang/jnigen/simple_package/Example$Nested$NestedTwice"); + if (_c_Example_Nested_NestedTwice == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Example_Nested_NestedTwice, + &_f_Example_Nested_NestedTwice__ZERO, "ZERO", "I"); + (*jniEnv)->SetStaticIntField(jniEnv, _c_Example_Nested_NestedTwice, + _f_Example_Nested_NestedTwice__ZERO, value); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +// com.github.dart_lang.jnigen.simple_package.Example$NonStaticNested +jclass _c_Example_NonStaticNested = NULL; + +jmethodID _m_Example_NonStaticNested__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult Example_NonStaticNested__new0(jobject _parent) { + load_env(); + load_class_global_ref( + &_c_Example_NonStaticNested, + "com/github/dart_lang/jnigen/simple_package/Example$NonStaticNested"); + if (_c_Example_NonStaticNested == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example_NonStaticNested, &_m_Example_NonStaticNested__new0, + "", + "(Lcom/github/dart_lang/jnigen/simple_package/Example;)V"); + if (_m_Example_NonStaticNested__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->NewObject(jniEnv, _c_Example_NonStaticNested, + _m_Example_NonStaticNested__new0, _parent); + return to_global_ref_result(_result); +} + +jfieldID _f_Example_NonStaticNested__ok = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Example_NonStaticNested__ok(jobject self_) { + load_env(); + load_class_global_ref( + &_c_Example_NonStaticNested, + "com/github/dart_lang/jnigen/simple_package/Example$NonStaticNested"); + if (_c_Example_NonStaticNested == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_Example_NonStaticNested, &_f_Example_NonStaticNested__ok, "ok", + "Z"); + uint8_t _result = + (*jniEnv)->GetBooleanField(jniEnv, self_, _f_Example_NonStaticNested__ok); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +FFI_PLUGIN_EXPORT +JniResult set_Example_NonStaticNested__ok(jobject self_, uint8_t value) { + load_env(); + load_class_global_ref( + &_c_Example_NonStaticNested, + "com/github/dart_lang/jnigen/simple_package/Example$NonStaticNested"); + if (_c_Example_NonStaticNested == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_Example_NonStaticNested, &_f_Example_NonStaticNested__ok, "ok", + "Z"); + (*jniEnv)->SetBooleanField(jniEnv, self_, _f_Example_NonStaticNested__ok, + value); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +// com.github.dart_lang.jnigen.simple_package.Exceptions +jclass _c_Exceptions = NULL; + +jmethodID _m_Exceptions__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult Exceptions__new0() { + load_env(); + load_class_global_ref( + &_c_Exceptions, "com/github/dart_lang/jnigen/simple_package/Exceptions"); + if (_c_Exceptions == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Exceptions, &_m_Exceptions__new0, "", "()V"); + if (_m_Exceptions__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->NewObject(jniEnv, _c_Exceptions, _m_Exceptions__new0); + return to_global_ref_result(_result); +} + +jmethodID _m_Exceptions__new1 = NULL; +FFI_PLUGIN_EXPORT +JniResult Exceptions__new1(float x) { + load_env(); + load_class_global_ref( + &_c_Exceptions, "com/github/dart_lang/jnigen/simple_package/Exceptions"); + if (_c_Exceptions == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Exceptions, &_m_Exceptions__new1, "", "(F)V"); + if (_m_Exceptions__new1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->NewObject(jniEnv, _c_Exceptions, _m_Exceptions__new1, x); + return to_global_ref_result(_result); +} + +jmethodID _m_Exceptions__new2 = NULL; +FFI_PLUGIN_EXPORT +JniResult Exceptions__new2(int32_t a, + int32_t b, + int32_t c, + int32_t d, + int32_t e, + int32_t f) { + load_env(); + load_class_global_ref( + &_c_Exceptions, "com/github/dart_lang/jnigen/simple_package/Exceptions"); + if (_c_Exceptions == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Exceptions, &_m_Exceptions__new2, "", "(IIIIII)V"); + if (_m_Exceptions__new2 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject(jniEnv, _c_Exceptions, + _m_Exceptions__new2, a, b, c, d, e, f); + return to_global_ref_result(_result); +} + +jmethodID _m_Exceptions__staticObjectMethod = NULL; +FFI_PLUGIN_EXPORT +JniResult Exceptions__staticObjectMethod() { + load_env(); + load_class_global_ref( + &_c_Exceptions, "com/github/dart_lang/jnigen/simple_package/Exceptions"); + if (_c_Exceptions == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_Exceptions, &_m_Exceptions__staticObjectMethod, + "staticObjectMethod", "()Ljava/lang/Object;"); + if (_m_Exceptions__staticObjectMethod == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_Exceptions, _m_Exceptions__staticObjectMethod); + return to_global_ref_result(_result); +} + +jmethodID _m_Exceptions__staticIntMethod = NULL; +FFI_PLUGIN_EXPORT +JniResult Exceptions__staticIntMethod() { + load_env(); + load_class_global_ref( + &_c_Exceptions, "com/github/dart_lang/jnigen/simple_package/Exceptions"); + if (_c_Exceptions == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_Exceptions, &_m_Exceptions__staticIntMethod, + "staticIntMethod", "()I"); + if (_m_Exceptions__staticIntMethod == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = (*jniEnv)->CallStaticIntMethod( + jniEnv, _c_Exceptions, _m_Exceptions__staticIntMethod); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_Exceptions__staticObjectArrayMethod = NULL; +FFI_PLUGIN_EXPORT +JniResult Exceptions__staticObjectArrayMethod() { + load_env(); + load_class_global_ref( + &_c_Exceptions, "com/github/dart_lang/jnigen/simple_package/Exceptions"); + if (_c_Exceptions == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_Exceptions, &_m_Exceptions__staticObjectArrayMethod, + "staticObjectArrayMethod", "()[Ljava/lang/Object;"); + if (_m_Exceptions__staticObjectArrayMethod == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_Exceptions, _m_Exceptions__staticObjectArrayMethod); + return to_global_ref_result(_result); +} + +jmethodID _m_Exceptions__staticIntArrayMethod = NULL; +FFI_PLUGIN_EXPORT +JniResult Exceptions__staticIntArrayMethod() { + load_env(); + load_class_global_ref( + &_c_Exceptions, "com/github/dart_lang/jnigen/simple_package/Exceptions"); + if (_c_Exceptions == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_Exceptions, &_m_Exceptions__staticIntArrayMethod, + "staticIntArrayMethod", "()[I"); + if (_m_Exceptions__staticIntArrayMethod == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_Exceptions, _m_Exceptions__staticIntArrayMethod); + return to_global_ref_result(_result); +} + +jmethodID _m_Exceptions__objectMethod = NULL; +FFI_PLUGIN_EXPORT +JniResult Exceptions__objectMethod(jobject self_) { + load_env(); + load_class_global_ref( + &_c_Exceptions, "com/github/dart_lang/jnigen/simple_package/Exceptions"); + if (_c_Exceptions == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Exceptions, &_m_Exceptions__objectMethod, "objectMethod", + "()Ljava/lang/Object;"); + if (_m_Exceptions__objectMethod == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_Exceptions__objectMethod); + return to_global_ref_result(_result); +} + +jmethodID _m_Exceptions__intMethod = NULL; +FFI_PLUGIN_EXPORT +JniResult Exceptions__intMethod(jobject self_) { + load_env(); + load_class_global_ref( + &_c_Exceptions, "com/github/dart_lang/jnigen/simple_package/Exceptions"); + if (_c_Exceptions == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Exceptions, &_m_Exceptions__intMethod, "intMethod", "()I"); + if (_m_Exceptions__intMethod == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = + (*jniEnv)->CallIntMethod(jniEnv, self_, _m_Exceptions__intMethod); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_Exceptions__objectArrayMethod = NULL; +FFI_PLUGIN_EXPORT +JniResult Exceptions__objectArrayMethod(jobject self_) { + load_env(); + load_class_global_ref( + &_c_Exceptions, "com/github/dart_lang/jnigen/simple_package/Exceptions"); + if (_c_Exceptions == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Exceptions, &_m_Exceptions__objectArrayMethod, + "objectArrayMethod", "()[Ljava/lang/Object;"); + if (_m_Exceptions__objectArrayMethod == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_Exceptions__objectArrayMethod); + return to_global_ref_result(_result); +} + +jmethodID _m_Exceptions__intArrayMethod = NULL; +FFI_PLUGIN_EXPORT +JniResult Exceptions__intArrayMethod(jobject self_) { + load_env(); + load_class_global_ref( + &_c_Exceptions, "com/github/dart_lang/jnigen/simple_package/Exceptions"); + if (_c_Exceptions == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Exceptions, &_m_Exceptions__intArrayMethod, "intArrayMethod", + "()[I"); + if (_m_Exceptions__intArrayMethod == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_Exceptions__intArrayMethod); + return to_global_ref_result(_result); +} + +jmethodID _m_Exceptions__throwNullPointerException = NULL; +FFI_PLUGIN_EXPORT +JniResult Exceptions__throwNullPointerException(jobject self_) { + load_env(); + load_class_global_ref( + &_c_Exceptions, "com/github/dart_lang/jnigen/simple_package/Exceptions"); + if (_c_Exceptions == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Exceptions, &_m_Exceptions__throwNullPointerException, + "throwNullPointerException", "()I"); + if (_m_Exceptions__throwNullPointerException == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = (*jniEnv)->CallIntMethod( + jniEnv, self_, _m_Exceptions__throwNullPointerException); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_Exceptions__throwFileNotFoundException = NULL; +FFI_PLUGIN_EXPORT +JniResult Exceptions__throwFileNotFoundException(jobject self_) { + load_env(); + load_class_global_ref( + &_c_Exceptions, "com/github/dart_lang/jnigen/simple_package/Exceptions"); + if (_c_Exceptions == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Exceptions, &_m_Exceptions__throwFileNotFoundException, + "throwFileNotFoundException", "()Ljava/io/InputStream;"); + if (_m_Exceptions__throwFileNotFoundException == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_Exceptions__throwFileNotFoundException); + return to_global_ref_result(_result); +} + +jmethodID _m_Exceptions__throwClassCastException = NULL; +FFI_PLUGIN_EXPORT +JniResult Exceptions__throwClassCastException(jobject self_) { + load_env(); + load_class_global_ref( + &_c_Exceptions, "com/github/dart_lang/jnigen/simple_package/Exceptions"); + if (_c_Exceptions == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Exceptions, &_m_Exceptions__throwClassCastException, + "throwClassCastException", "()Ljava/io/FileInputStream;"); + if (_m_Exceptions__throwClassCastException == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_Exceptions__throwClassCastException); + return to_global_ref_result(_result); +} + +jmethodID _m_Exceptions__throwArrayIndexException = NULL; +FFI_PLUGIN_EXPORT +JniResult Exceptions__throwArrayIndexException(jobject self_) { + load_env(); + load_class_global_ref( + &_c_Exceptions, "com/github/dart_lang/jnigen/simple_package/Exceptions"); + if (_c_Exceptions == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Exceptions, &_m_Exceptions__throwArrayIndexException, + "throwArrayIndexException", "()I"); + if (_m_Exceptions__throwArrayIndexException == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = (*jniEnv)->CallIntMethod( + jniEnv, self_, _m_Exceptions__throwArrayIndexException); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_Exceptions__throwArithmeticException = NULL; +FFI_PLUGIN_EXPORT +JniResult Exceptions__throwArithmeticException(jobject self_) { + load_env(); + load_class_global_ref( + &_c_Exceptions, "com/github/dart_lang/jnigen/simple_package/Exceptions"); + if (_c_Exceptions == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Exceptions, &_m_Exceptions__throwArithmeticException, + "throwArithmeticException", "()I"); + if (_m_Exceptions__throwArithmeticException == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = (*jniEnv)->CallIntMethod( + jniEnv, self_, _m_Exceptions__throwArithmeticException); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +jmethodID _m_Exceptions__throwLoremIpsum = NULL; +FFI_PLUGIN_EXPORT +JniResult Exceptions__throwLoremIpsum() { + load_env(); + load_class_global_ref( + &_c_Exceptions, "com/github/dart_lang/jnigen/simple_package/Exceptions"); + if (_c_Exceptions == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_Exceptions, &_m_Exceptions__throwLoremIpsum, + "throwLoremIpsum", "()V"); + if (_m_Exceptions__throwLoremIpsum == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallStaticVoidMethod(jniEnv, _c_Exceptions, + _m_Exceptions__throwLoremIpsum); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +// com.github.dart_lang.jnigen.simple_package.Fields +jclass _c_Fields = NULL; + +jmethodID _m_Fields__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult Fields__new0() { + load_env(); + load_class_global_ref(&_c_Fields, + "com/github/dart_lang/jnigen/simple_package/Fields"); + if (_c_Fields == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Fields, &_m_Fields__new0, "", "()V"); + if (_m_Fields__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject(jniEnv, _c_Fields, _m_Fields__new0); + return to_global_ref_result(_result); +} + +jfieldID _f_Fields__amount = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Fields__amount() { + load_env(); + load_class_global_ref(&_c_Fields, + "com/github/dart_lang/jnigen/simple_package/Fields"); + if (_c_Fields == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Fields, &_f_Fields__amount, "amount", "I"); + int32_t _result = + (*jniEnv)->GetStaticIntField(jniEnv, _c_Fields, _f_Fields__amount); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +FFI_PLUGIN_EXPORT +JniResult set_Fields__amount(int32_t value) { + load_env(); + load_class_global_ref(&_c_Fields, + "com/github/dart_lang/jnigen/simple_package/Fields"); + if (_c_Fields == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Fields, &_f_Fields__amount, "amount", "I"); + (*jniEnv)->SetStaticIntField(jniEnv, _c_Fields, _f_Fields__amount, value); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jfieldID _f_Fields__pi = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Fields__pi() { + load_env(); + load_class_global_ref(&_c_Fields, + "com/github/dart_lang/jnigen/simple_package/Fields"); + if (_c_Fields == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Fields, &_f_Fields__pi, "pi", "D"); + double _result = + (*jniEnv)->GetStaticDoubleField(jniEnv, _c_Fields, _f_Fields__pi); + return (JniResult){.value = {.d = _result}, .exception = check_exception()}; +} + +FFI_PLUGIN_EXPORT +JniResult set_Fields__pi(double value) { + load_env(); + load_class_global_ref(&_c_Fields, + "com/github/dart_lang/jnigen/simple_package/Fields"); + if (_c_Fields == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Fields, &_f_Fields__pi, "pi", "D"); + (*jniEnv)->SetStaticDoubleField(jniEnv, _c_Fields, _f_Fields__pi, value); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jfieldID _f_Fields__asterisk = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Fields__asterisk() { + load_env(); + load_class_global_ref(&_c_Fields, + "com/github/dart_lang/jnigen/simple_package/Fields"); + if (_c_Fields == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Fields, &_f_Fields__asterisk, "asterisk", "C"); + uint16_t _result = + (*jniEnv)->GetStaticCharField(jniEnv, _c_Fields, _f_Fields__asterisk); + return (JniResult){.value = {.c = _result}, .exception = check_exception()}; +} + +FFI_PLUGIN_EXPORT +JniResult set_Fields__asterisk(uint16_t value) { + load_env(); + load_class_global_ref(&_c_Fields, + "com/github/dart_lang/jnigen/simple_package/Fields"); + if (_c_Fields == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Fields, &_f_Fields__asterisk, "asterisk", "C"); + (*jniEnv)->SetStaticCharField(jniEnv, _c_Fields, _f_Fields__asterisk, value); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jfieldID _f_Fields__name = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Fields__name() { + load_env(); + load_class_global_ref(&_c_Fields, + "com/github/dart_lang/jnigen/simple_package/Fields"); + if (_c_Fields == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Fields, &_f_Fields__name, "name", "Ljava/lang/String;"); + jobject _result = + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Fields, _f_Fields__name); + return to_global_ref_result(_result); +} + +FFI_PLUGIN_EXPORT +JniResult set_Fields__name(jobject value) { + load_env(); + load_class_global_ref(&_c_Fields, + "com/github/dart_lang/jnigen/simple_package/Fields"); + if (_c_Fields == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Fields, &_f_Fields__name, "name", "Ljava/lang/String;"); + (*jniEnv)->SetStaticObjectField(jniEnv, _c_Fields, _f_Fields__name, value); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jfieldID _f_Fields__i = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Fields__i(jobject self_) { + load_env(); + load_class_global_ref(&_c_Fields, + "com/github/dart_lang/jnigen/simple_package/Fields"); + if (_c_Fields == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_Fields, &_f_Fields__i, "i", "Ljava/lang/Integer;"); + jobject _result = (*jniEnv)->GetObjectField(jniEnv, self_, _f_Fields__i); + return to_global_ref_result(_result); +} + +FFI_PLUGIN_EXPORT +JniResult set_Fields__i(jobject self_, jobject value) { + load_env(); + load_class_global_ref(&_c_Fields, + "com/github/dart_lang/jnigen/simple_package/Fields"); + if (_c_Fields == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_Fields, &_f_Fields__i, "i", "Ljava/lang/Integer;"); + (*jniEnv)->SetObjectField(jniEnv, self_, _f_Fields__i, value); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jfieldID _f_Fields__trillion = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Fields__trillion(jobject self_) { + load_env(); + load_class_global_ref(&_c_Fields, + "com/github/dart_lang/jnigen/simple_package/Fields"); + if (_c_Fields == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_Fields, &_f_Fields__trillion, "trillion", "J"); + int64_t _result = (*jniEnv)->GetLongField(jniEnv, self_, _f_Fields__trillion); + return (JniResult){.value = {.j = _result}, .exception = check_exception()}; +} + +FFI_PLUGIN_EXPORT +JniResult set_Fields__trillion(jobject self_, int64_t value) { + load_env(); + load_class_global_ref(&_c_Fields, + "com/github/dart_lang/jnigen/simple_package/Fields"); + if (_c_Fields == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_Fields, &_f_Fields__trillion, "trillion", "J"); + (*jniEnv)->SetLongField(jniEnv, self_, _f_Fields__trillion, value); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jfieldID _f_Fields__isAchillesDead = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Fields__isAchillesDead(jobject self_) { + load_env(); + load_class_global_ref(&_c_Fields, + "com/github/dart_lang/jnigen/simple_package/Fields"); + if (_c_Fields == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_Fields, &_f_Fields__isAchillesDead, "isAchillesDead", "Z"); + uint8_t _result = + (*jniEnv)->GetBooleanField(jniEnv, self_, _f_Fields__isAchillesDead); + return (JniResult){.value = {.z = _result}, .exception = check_exception()}; +} + +FFI_PLUGIN_EXPORT +JniResult set_Fields__isAchillesDead(jobject self_, uint8_t value) { + load_env(); + load_class_global_ref(&_c_Fields, + "com/github/dart_lang/jnigen/simple_package/Fields"); + if (_c_Fields == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_Fields, &_f_Fields__isAchillesDead, "isAchillesDead", "Z"); + (*jniEnv)->SetBooleanField(jniEnv, self_, _f_Fields__isAchillesDead, value); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jfieldID _f_Fields__bestFighterInGreece = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Fields__bestFighterInGreece(jobject self_) { + load_env(); + load_class_global_ref(&_c_Fields, + "com/github/dart_lang/jnigen/simple_package/Fields"); + if (_c_Fields == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_Fields, &_f_Fields__bestFighterInGreece, "bestFighterInGreece", + "Ljava/lang/String;"); + jobject _result = + (*jniEnv)->GetObjectField(jniEnv, self_, _f_Fields__bestFighterInGreece); + return to_global_ref_result(_result); +} + +FFI_PLUGIN_EXPORT +JniResult set_Fields__bestFighterInGreece(jobject self_, jobject value) { + load_env(); + load_class_global_ref(&_c_Fields, + "com/github/dart_lang/jnigen/simple_package/Fields"); + if (_c_Fields == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_Fields, &_f_Fields__bestFighterInGreece, "bestFighterInGreece", + "Ljava/lang/String;"); + (*jniEnv)->SetObjectField(jniEnv, self_, _f_Fields__bestFighterInGreece, + value); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jfieldID _f_Fields__random = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Fields__random(jobject self_) { + load_env(); + load_class_global_ref(&_c_Fields, + "com/github/dart_lang/jnigen/simple_package/Fields"); + if (_c_Fields == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_Fields, &_f_Fields__random, "random", "Ljava/util/Random;"); + jobject _result = (*jniEnv)->GetObjectField(jniEnv, self_, _f_Fields__random); + return to_global_ref_result(_result); +} + +FFI_PLUGIN_EXPORT +JniResult set_Fields__random(jobject self_, jobject value) { + load_env(); + load_class_global_ref(&_c_Fields, + "com/github/dart_lang/jnigen/simple_package/Fields"); + if (_c_Fields == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_Fields, &_f_Fields__random, "random", "Ljava/util/Random;"); + (*jniEnv)->SetObjectField(jniEnv, self_, _f_Fields__random, value); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jfieldID _f_Fields__euroSymbol = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Fields__euroSymbol() { + load_env(); + load_class_global_ref(&_c_Fields, + "com/github/dart_lang/jnigen/simple_package/Fields"); + if (_c_Fields == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Fields, &_f_Fields__euroSymbol, "euroSymbol", "C"); + uint16_t _result = + (*jniEnv)->GetStaticCharField(jniEnv, _c_Fields, _f_Fields__euroSymbol); + return (JniResult){.value = {.c = _result}, .exception = check_exception()}; +} + +FFI_PLUGIN_EXPORT +JniResult set_Fields__euroSymbol(uint16_t value) { + load_env(); + load_class_global_ref(&_c_Fields, + "com/github/dart_lang/jnigen/simple_package/Fields"); + if (_c_Fields == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Fields, &_f_Fields__euroSymbol, "euroSymbol", "C"); + (*jniEnv)->SetStaticCharField(jniEnv, _c_Fields, _f_Fields__euroSymbol, + value); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +// com.github.dart_lang.jnigen.simple_package.Fields$Nested +jclass _c_Fields_Nested = NULL; + +jmethodID _m_Fields_Nested__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult Fields_Nested__new0() { + load_env(); + load_class_global_ref( + &_c_Fields_Nested, + "com/github/dart_lang/jnigen/simple_package/Fields$Nested"); + if (_c_Fields_Nested == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Fields_Nested, &_m_Fields_Nested__new0, "", "()V"); + if (_m_Fields_Nested__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->NewObject(jniEnv, _c_Fields_Nested, _m_Fields_Nested__new0); + return to_global_ref_result(_result); +} + +jfieldID _f_Fields_Nested__hundred = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Fields_Nested__hundred(jobject self_) { + load_env(); + load_class_global_ref( + &_c_Fields_Nested, + "com/github/dart_lang/jnigen/simple_package/Fields$Nested"); + if (_c_Fields_Nested == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_Fields_Nested, &_f_Fields_Nested__hundred, "hundred", "J"); + int64_t _result = + (*jniEnv)->GetLongField(jniEnv, self_, _f_Fields_Nested__hundred); + return (JniResult){.value = {.j = _result}, .exception = check_exception()}; +} + +FFI_PLUGIN_EXPORT +JniResult set_Fields_Nested__hundred(jobject self_, int64_t value) { + load_env(); + load_class_global_ref( + &_c_Fields_Nested, + "com/github/dart_lang/jnigen/simple_package/Fields$Nested"); + if (_c_Fields_Nested == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_Fields_Nested, &_f_Fields_Nested__hundred, "hundred", "J"); + (*jniEnv)->SetLongField(jniEnv, self_, _f_Fields_Nested__hundred, value); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jfieldID _f_Fields_Nested__BEST_GOD = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Fields_Nested__BEST_GOD() { + load_env(); + load_class_global_ref( + &_c_Fields_Nested, + "com/github/dart_lang/jnigen/simple_package/Fields$Nested"); + if (_c_Fields_Nested == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Fields_Nested, &_f_Fields_Nested__BEST_GOD, "BEST_GOD", + "Ljava/lang/String;"); + jobject _result = (*jniEnv)->GetStaticObjectField(jniEnv, _c_Fields_Nested, + _f_Fields_Nested__BEST_GOD); + return to_global_ref_result(_result); +} + +FFI_PLUGIN_EXPORT +JniResult set_Fields_Nested__BEST_GOD(jobject value) { + load_env(); + load_class_global_ref( + &_c_Fields_Nested, + "com/github/dart_lang/jnigen/simple_package/Fields$Nested"); + if (_c_Fields_Nested == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Fields_Nested, &_f_Fields_Nested__BEST_GOD, "BEST_GOD", + "Ljava/lang/String;"); + (*jniEnv)->SetStaticObjectField(jniEnv, _c_Fields_Nested, + _f_Fields_Nested__BEST_GOD, value); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +// com.github.dart_lang.jnigen.pkg2.C2 +jclass _c_C2 = NULL; + +jmethodID _m_C2__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult C2__new0() { + load_env(); + load_class_global_ref(&_c_C2, "com/github/dart_lang/jnigen/pkg2/C2"); + if (_c_C2 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_C2, &_m_C2__new0, "", "()V"); + if (_m_C2__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject(jniEnv, _c_C2, _m_C2__new0); + return to_global_ref_result(_result); +} + +jfieldID _f_C2__CONSTANT = NULL; +FFI_PLUGIN_EXPORT +JniResult get_C2__CONSTANT() { + load_env(); + load_class_global_ref(&_c_C2, "com/github/dart_lang/jnigen/pkg2/C2"); + if (_c_C2 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_C2, &_f_C2__CONSTANT, "CONSTANT", "I"); + int32_t _result = + (*jniEnv)->GetStaticIntField(jniEnv, _c_C2, _f_C2__CONSTANT); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +FFI_PLUGIN_EXPORT +JniResult set_C2__CONSTANT(int32_t value) { + load_env(); + load_class_global_ref(&_c_C2, "com/github/dart_lang/jnigen/pkg2/C2"); + if (_c_C2 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_C2, &_f_C2__CONSTANT, "CONSTANT", "I"); + (*jniEnv)->SetStaticIntField(jniEnv, _c_C2, _f_C2__CONSTANT, value); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +// com.github.dart_lang.jnigen.pkg2.Example +jclass _c_Example1 = NULL; + +jmethodID _m_Example1__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult Example1__new0() { + load_env(); + load_class_global_ref(&_c_Example1, + "com/github/dart_lang/jnigen/pkg2/Example"); + if (_c_Example1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example1, &_m_Example1__new0, "", "()V"); + if (_m_Example1__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->NewObject(jniEnv, _c_Example1, _m_Example1__new0); + return to_global_ref_result(_result); +} + +jmethodID _m_Example1__whichExample = NULL; +FFI_PLUGIN_EXPORT +JniResult Example1__whichExample(jobject self_) { + load_env(); + load_class_global_ref(&_c_Example1, + "com/github/dart_lang/jnigen/pkg2/Example"); + if (_c_Example1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_Example1, &_m_Example1__whichExample, "whichExample", "()I"); + if (_m_Example1__whichExample == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = + (*jniEnv)->CallIntMethod(jniEnv, self_, _m_Example1__whichExample); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +// com.github.dart_lang.jnigen.generics.GenericTypeParams +jclass _c_GenericTypeParams = NULL; + +jmethodID _m_GenericTypeParams__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult GenericTypeParams__new0() { + load_env(); + load_class_global_ref( + &_c_GenericTypeParams, + "com/github/dart_lang/jnigen/generics/GenericTypeParams"); + if (_c_GenericTypeParams == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_GenericTypeParams, &_m_GenericTypeParams__new0, "", + "()V"); + if (_m_GenericTypeParams__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject(jniEnv, _c_GenericTypeParams, + _m_GenericTypeParams__new0); + return to_global_ref_result(_result); +} + +// com.github.dart_lang.jnigen.generics.GrandParent +jclass _c_GrandParent = NULL; + +jmethodID _m_GrandParent__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult GrandParent__new0(jobject value) { + load_env(); + load_class_global_ref(&_c_GrandParent, + "com/github/dart_lang/jnigen/generics/GrandParent"); + if (_c_GrandParent == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_GrandParent, &_m_GrandParent__new0, "", + "(Ljava/lang/Object;)V"); + if (_m_GrandParent__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->NewObject(jniEnv, _c_GrandParent, _m_GrandParent__new0, value); + return to_global_ref_result(_result); +} + +jmethodID _m_GrandParent__stringParent = NULL; +FFI_PLUGIN_EXPORT +JniResult GrandParent__stringParent(jobject self_) { + load_env(); + load_class_global_ref(&_c_GrandParent, + "com/github/dart_lang/jnigen/generics/GrandParent"); + if (_c_GrandParent == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_GrandParent, &_m_GrandParent__stringParent, "stringParent", + "()Lcom/github/dart_lang/jnigen/generics/GrandParent$Parent;"); + if (_m_GrandParent__stringParent == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_GrandParent__stringParent); + return to_global_ref_result(_result); +} + +jmethodID _m_GrandParent__varParent = NULL; +FFI_PLUGIN_EXPORT +JniResult GrandParent__varParent(jobject self_, jobject nestedValue) { + load_env(); + load_class_global_ref(&_c_GrandParent, + "com/github/dart_lang/jnigen/generics/GrandParent"); + if (_c_GrandParent == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_GrandParent, &_m_GrandParent__varParent, "varParent", + "(Ljava/lang/Object;)Lcom/github/dart_lang/jnigen/generics/" + "GrandParent$Parent;"); + if (_m_GrandParent__varParent == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_GrandParent__varParent, nestedValue); + return to_global_ref_result(_result); +} + +jmethodID _m_GrandParent__stringStaticParent = NULL; +FFI_PLUGIN_EXPORT +JniResult GrandParent__stringStaticParent() { + load_env(); + load_class_global_ref(&_c_GrandParent, + "com/github/dart_lang/jnigen/generics/GrandParent"); + if (_c_GrandParent == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method( + _c_GrandParent, &_m_GrandParent__stringStaticParent, "stringStaticParent", + "()Lcom/github/dart_lang/jnigen/generics/GrandParent$StaticParent;"); + if (_m_GrandParent__stringStaticParent == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_GrandParent, _m_GrandParent__stringStaticParent); + return to_global_ref_result(_result); +} + +jmethodID _m_GrandParent__varStaticParent = NULL; +FFI_PLUGIN_EXPORT +JniResult GrandParent__varStaticParent(jobject value) { + load_env(); + load_class_global_ref(&_c_GrandParent, + "com/github/dart_lang/jnigen/generics/GrandParent"); + if (_c_GrandParent == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_GrandParent, &_m_GrandParent__varStaticParent, + "varStaticParent", + "(Ljava/lang/Object;)Lcom/github/dart_lang/jnigen/" + "generics/GrandParent$StaticParent;"); + if (_m_GrandParent__varStaticParent == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_GrandParent, _m_GrandParent__varStaticParent, value); + return to_global_ref_result(_result); +} + +jmethodID _m_GrandParent__staticParentWithSameType = NULL; +FFI_PLUGIN_EXPORT +JniResult GrandParent__staticParentWithSameType(jobject self_) { + load_env(); + load_class_global_ref(&_c_GrandParent, + "com/github/dart_lang/jnigen/generics/GrandParent"); + if (_c_GrandParent == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method( + _c_GrandParent, &_m_GrandParent__staticParentWithSameType, + "staticParentWithSameType", + "()Lcom/github/dart_lang/jnigen/generics/GrandParent$StaticParent;"); + if (_m_GrandParent__staticParentWithSameType == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_GrandParent__staticParentWithSameType); + return to_global_ref_result(_result); +} + +jfieldID _f_GrandParent__value = NULL; +FFI_PLUGIN_EXPORT +JniResult get_GrandParent__value(jobject self_) { + load_env(); + load_class_global_ref(&_c_GrandParent, + "com/github/dart_lang/jnigen/generics/GrandParent"); + if (_c_GrandParent == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_GrandParent, &_f_GrandParent__value, "value", + "Ljava/lang/Object;"); + jobject _result = + (*jniEnv)->GetObjectField(jniEnv, self_, _f_GrandParent__value); + return to_global_ref_result(_result); +} + +FFI_PLUGIN_EXPORT +JniResult set_GrandParent__value(jobject self_, jobject value) { + load_env(); + load_class_global_ref(&_c_GrandParent, + "com/github/dart_lang/jnigen/generics/GrandParent"); + if (_c_GrandParent == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_GrandParent, &_f_GrandParent__value, "value", + "Ljava/lang/Object;"); + (*jniEnv)->SetObjectField(jniEnv, self_, _f_GrandParent__value, value); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +// com.github.dart_lang.jnigen.generics.GrandParent$Parent +jclass _c_GrandParent_Parent = NULL; + +jmethodID _m_GrandParent_Parent__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult GrandParent_Parent__new0(jobject _parent, jobject newValue) { + load_env(); + load_class_global_ref( + &_c_GrandParent_Parent, + "com/github/dart_lang/jnigen/generics/GrandParent$Parent"); + if (_c_GrandParent_Parent == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_GrandParent_Parent, &_m_GrandParent_Parent__new0, "", + "(Lcom/github/dart_lang/jnigen/generics/GrandParent;Ljava/lang/" + "Object;)V"); + if (_m_GrandParent_Parent__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->NewObject(jniEnv, _c_GrandParent_Parent, + _m_GrandParent_Parent__new0, _parent, newValue); + return to_global_ref_result(_result); +} + +jfieldID _f_GrandParent_Parent__parentValue = NULL; +FFI_PLUGIN_EXPORT +JniResult get_GrandParent_Parent__parentValue(jobject self_) { + load_env(); + load_class_global_ref( + &_c_GrandParent_Parent, + "com/github/dart_lang/jnigen/generics/GrandParent$Parent"); + if (_c_GrandParent_Parent == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_GrandParent_Parent, &_f_GrandParent_Parent__parentValue, + "parentValue", "Ljava/lang/Object;"); + jobject _result = (*jniEnv)->GetObjectField( + jniEnv, self_, _f_GrandParent_Parent__parentValue); + return to_global_ref_result(_result); +} + +FFI_PLUGIN_EXPORT +JniResult set_GrandParent_Parent__parentValue(jobject self_, jobject value) { + load_env(); + load_class_global_ref( + &_c_GrandParent_Parent, + "com/github/dart_lang/jnigen/generics/GrandParent$Parent"); + if (_c_GrandParent_Parent == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_GrandParent_Parent, &_f_GrandParent_Parent__parentValue, + "parentValue", "Ljava/lang/Object;"); + (*jniEnv)->SetObjectField(jniEnv, self_, _f_GrandParent_Parent__parentValue, + value); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jfieldID _f_GrandParent_Parent__value = NULL; +FFI_PLUGIN_EXPORT +JniResult get_GrandParent_Parent__value(jobject self_) { + load_env(); + load_class_global_ref( + &_c_GrandParent_Parent, + "com/github/dart_lang/jnigen/generics/GrandParent$Parent"); + if (_c_GrandParent_Parent == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_GrandParent_Parent, &_f_GrandParent_Parent__value, "value", + "Ljava/lang/Object;"); + jobject _result = + (*jniEnv)->GetObjectField(jniEnv, self_, _f_GrandParent_Parent__value); + return to_global_ref_result(_result); +} + +FFI_PLUGIN_EXPORT +JniResult set_GrandParent_Parent__value(jobject self_, jobject value) { + load_env(); + load_class_global_ref( + &_c_GrandParent_Parent, + "com/github/dart_lang/jnigen/generics/GrandParent$Parent"); + if (_c_GrandParent_Parent == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_GrandParent_Parent, &_f_GrandParent_Parent__value, "value", + "Ljava/lang/Object;"); + (*jniEnv)->SetObjectField(jniEnv, self_, _f_GrandParent_Parent__value, value); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +// com.github.dart_lang.jnigen.generics.GrandParent$Parent$Child +jclass _c_GrandParent_Parent_Child = NULL; + +jmethodID _m_GrandParent_Parent_Child__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult GrandParent_Parent_Child__new0(jobject _parent, jobject newValue) { + load_env(); + load_class_global_ref( + &_c_GrandParent_Parent_Child, + "com/github/dart_lang/jnigen/generics/GrandParent$Parent$Child"); + if (_c_GrandParent_Parent_Child == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_GrandParent_Parent_Child, &_m_GrandParent_Parent_Child__new0, + "", + "(Lcom/github/dart_lang/jnigen/generics/GrandParent$Parent;Ljava/" + "lang/Object;)V"); + if (_m_GrandParent_Parent_Child__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject(jniEnv, _c_GrandParent_Parent_Child, + _m_GrandParent_Parent_Child__new0, + _parent, newValue); + return to_global_ref_result(_result); +} + +jfieldID _f_GrandParent_Parent_Child__grandParentValue = NULL; +FFI_PLUGIN_EXPORT +JniResult get_GrandParent_Parent_Child__grandParentValue(jobject self_) { + load_env(); + load_class_global_ref( + &_c_GrandParent_Parent_Child, + "com/github/dart_lang/jnigen/generics/GrandParent$Parent$Child"); + if (_c_GrandParent_Parent_Child == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_GrandParent_Parent_Child, + &_f_GrandParent_Parent_Child__grandParentValue, "grandParentValue", + "Ljava/lang/Object;"); + jobject _result = (*jniEnv)->GetObjectField( + jniEnv, self_, _f_GrandParent_Parent_Child__grandParentValue); + return to_global_ref_result(_result); +} + +FFI_PLUGIN_EXPORT +JniResult set_GrandParent_Parent_Child__grandParentValue(jobject self_, + jobject value) { + load_env(); + load_class_global_ref( + &_c_GrandParent_Parent_Child, + "com/github/dart_lang/jnigen/generics/GrandParent$Parent$Child"); + if (_c_GrandParent_Parent_Child == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_GrandParent_Parent_Child, + &_f_GrandParent_Parent_Child__grandParentValue, "grandParentValue", + "Ljava/lang/Object;"); + (*jniEnv)->SetObjectField( + jniEnv, self_, _f_GrandParent_Parent_Child__grandParentValue, value); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jfieldID _f_GrandParent_Parent_Child__parentValue = NULL; +FFI_PLUGIN_EXPORT +JniResult get_GrandParent_Parent_Child__parentValue(jobject self_) { + load_env(); + load_class_global_ref( + &_c_GrandParent_Parent_Child, + "com/github/dart_lang/jnigen/generics/GrandParent$Parent$Child"); + if (_c_GrandParent_Parent_Child == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_GrandParent_Parent_Child, + &_f_GrandParent_Parent_Child__parentValue, "parentValue", + "Ljava/lang/Object;"); + jobject _result = (*jniEnv)->GetObjectField( + jniEnv, self_, _f_GrandParent_Parent_Child__parentValue); + return to_global_ref_result(_result); +} + +FFI_PLUGIN_EXPORT +JniResult set_GrandParent_Parent_Child__parentValue(jobject self_, + jobject value) { + load_env(); + load_class_global_ref( + &_c_GrandParent_Parent_Child, + "com/github/dart_lang/jnigen/generics/GrandParent$Parent$Child"); + if (_c_GrandParent_Parent_Child == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_GrandParent_Parent_Child, + &_f_GrandParent_Parent_Child__parentValue, "parentValue", + "Ljava/lang/Object;"); + (*jniEnv)->SetObjectField(jniEnv, self_, + _f_GrandParent_Parent_Child__parentValue, value); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jfieldID _f_GrandParent_Parent_Child__value = NULL; +FFI_PLUGIN_EXPORT +JniResult get_GrandParent_Parent_Child__value(jobject self_) { + load_env(); + load_class_global_ref( + &_c_GrandParent_Parent_Child, + "com/github/dart_lang/jnigen/generics/GrandParent$Parent$Child"); + if (_c_GrandParent_Parent_Child == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_GrandParent_Parent_Child, &_f_GrandParent_Parent_Child__value, + "value", "Ljava/lang/Object;"); + jobject _result = (*jniEnv)->GetObjectField( + jniEnv, self_, _f_GrandParent_Parent_Child__value); + return to_global_ref_result(_result); +} + +FFI_PLUGIN_EXPORT +JniResult set_GrandParent_Parent_Child__value(jobject self_, jobject value) { + load_env(); + load_class_global_ref( + &_c_GrandParent_Parent_Child, + "com/github/dart_lang/jnigen/generics/GrandParent$Parent$Child"); + if (_c_GrandParent_Parent_Child == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_GrandParent_Parent_Child, &_f_GrandParent_Parent_Child__value, + "value", "Ljava/lang/Object;"); + (*jniEnv)->SetObjectField(jniEnv, self_, _f_GrandParent_Parent_Child__value, + value); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +// com.github.dart_lang.jnigen.generics.GrandParent$StaticParent +jclass _c_GrandParent_StaticParent = NULL; + +jmethodID _m_GrandParent_StaticParent__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult GrandParent_StaticParent__new0(jobject value) { + load_env(); + load_class_global_ref( + &_c_GrandParent_StaticParent, + "com/github/dart_lang/jnigen/generics/GrandParent$StaticParent"); + if (_c_GrandParent_StaticParent == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_GrandParent_StaticParent, &_m_GrandParent_StaticParent__new0, + "", "(Ljava/lang/Object;)V"); + if (_m_GrandParent_StaticParent__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->NewObject(jniEnv, _c_GrandParent_StaticParent, + _m_GrandParent_StaticParent__new0, value); + return to_global_ref_result(_result); +} + +jfieldID _f_GrandParent_StaticParent__value = NULL; +FFI_PLUGIN_EXPORT +JniResult get_GrandParent_StaticParent__value(jobject self_) { + load_env(); + load_class_global_ref( + &_c_GrandParent_StaticParent, + "com/github/dart_lang/jnigen/generics/GrandParent$StaticParent"); + if (_c_GrandParent_StaticParent == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_GrandParent_StaticParent, &_f_GrandParent_StaticParent__value, + "value", "Ljava/lang/Object;"); + jobject _result = (*jniEnv)->GetObjectField( + jniEnv, self_, _f_GrandParent_StaticParent__value); + return to_global_ref_result(_result); +} + +FFI_PLUGIN_EXPORT +JniResult set_GrandParent_StaticParent__value(jobject self_, jobject value) { + load_env(); + load_class_global_ref( + &_c_GrandParent_StaticParent, + "com/github/dart_lang/jnigen/generics/GrandParent$StaticParent"); + if (_c_GrandParent_StaticParent == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_GrandParent_StaticParent, &_f_GrandParent_StaticParent__value, + "value", "Ljava/lang/Object;"); + (*jniEnv)->SetObjectField(jniEnv, self_, _f_GrandParent_StaticParent__value, + value); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +// com.github.dart_lang.jnigen.generics.GrandParent$StaticParent$Child +jclass _c_GrandParent_StaticParent_Child = NULL; + +jmethodID _m_GrandParent_StaticParent_Child__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult GrandParent_StaticParent_Child__new0(jobject _parent, + jobject parentValue, + jobject value) { + load_env(); + load_class_global_ref( + &_c_GrandParent_StaticParent_Child, + "com/github/dart_lang/jnigen/generics/GrandParent$StaticParent$Child"); + if (_c_GrandParent_StaticParent_Child == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method( + _c_GrandParent_StaticParent_Child, + &_m_GrandParent_StaticParent_Child__new0, "", + "(Lcom/github/dart_lang/jnigen/generics/GrandParent$StaticParent;Ljava/" + "lang/Object;Ljava/lang/Object;)V"); + if (_m_GrandParent_StaticParent_Child__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject( + jniEnv, _c_GrandParent_StaticParent_Child, + _m_GrandParent_StaticParent_Child__new0, _parent, parentValue, value); + return to_global_ref_result(_result); +} + +jfieldID _f_GrandParent_StaticParent_Child__parentValue = NULL; +FFI_PLUGIN_EXPORT +JniResult get_GrandParent_StaticParent_Child__parentValue(jobject self_) { + load_env(); + load_class_global_ref( + &_c_GrandParent_StaticParent_Child, + "com/github/dart_lang/jnigen/generics/GrandParent$StaticParent$Child"); + if (_c_GrandParent_StaticParent_Child == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_GrandParent_StaticParent_Child, + &_f_GrandParent_StaticParent_Child__parentValue, "parentValue", + "Ljava/lang/Object;"); + jobject _result = (*jniEnv)->GetObjectField( + jniEnv, self_, _f_GrandParent_StaticParent_Child__parentValue); + return to_global_ref_result(_result); +} + +FFI_PLUGIN_EXPORT +JniResult set_GrandParent_StaticParent_Child__parentValue(jobject self_, + jobject value) { + load_env(); + load_class_global_ref( + &_c_GrandParent_StaticParent_Child, + "com/github/dart_lang/jnigen/generics/GrandParent$StaticParent$Child"); + if (_c_GrandParent_StaticParent_Child == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_GrandParent_StaticParent_Child, + &_f_GrandParent_StaticParent_Child__parentValue, "parentValue", + "Ljava/lang/Object;"); + (*jniEnv)->SetObjectField( + jniEnv, self_, _f_GrandParent_StaticParent_Child__parentValue, value); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jfieldID _f_GrandParent_StaticParent_Child__value = NULL; +FFI_PLUGIN_EXPORT +JniResult get_GrandParent_StaticParent_Child__value(jobject self_) { + load_env(); + load_class_global_ref( + &_c_GrandParent_StaticParent_Child, + "com/github/dart_lang/jnigen/generics/GrandParent$StaticParent$Child"); + if (_c_GrandParent_StaticParent_Child == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_GrandParent_StaticParent_Child, + &_f_GrandParent_StaticParent_Child__value, "value", + "Ljava/lang/Object;"); + jobject _result = (*jniEnv)->GetObjectField( + jniEnv, self_, _f_GrandParent_StaticParent_Child__value); + return to_global_ref_result(_result); +} + +FFI_PLUGIN_EXPORT +JniResult set_GrandParent_StaticParent_Child__value(jobject self_, + jobject value) { + load_env(); + load_class_global_ref( + &_c_GrandParent_StaticParent_Child, + "com/github/dart_lang/jnigen/generics/GrandParent$StaticParent$Child"); + if (_c_GrandParent_StaticParent_Child == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_GrandParent_StaticParent_Child, + &_f_GrandParent_StaticParent_Child__value, "value", + "Ljava/lang/Object;"); + (*jniEnv)->SetObjectField(jniEnv, self_, + _f_GrandParent_StaticParent_Child__value, value); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +// com.github.dart_lang.jnigen.generics.MyMap +jclass _c_MyMap = NULL; + +jmethodID _m_MyMap__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult MyMap__new0() { + load_env(); + load_class_global_ref(&_c_MyMap, + "com/github/dart_lang/jnigen/generics/MyMap"); + if (_c_MyMap == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_MyMap, &_m_MyMap__new0, "", "()V"); + if (_m_MyMap__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject(jniEnv, _c_MyMap, _m_MyMap__new0); + return to_global_ref_result(_result); +} + +jmethodID _m_MyMap__get0 = NULL; +FFI_PLUGIN_EXPORT +JniResult MyMap__get0(jobject self_, jobject key) { + load_env(); + load_class_global_ref(&_c_MyMap, + "com/github/dart_lang/jnigen/generics/MyMap"); + if (_c_MyMap == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_MyMap, &_m_MyMap__get0, "get", + "(Ljava/lang/Object;)Ljava/lang/Object;"); + if (_m_MyMap__get0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_MyMap__get0, key); + return to_global_ref_result(_result); +} + +jmethodID _m_MyMap__put = NULL; +FFI_PLUGIN_EXPORT +JniResult MyMap__put(jobject self_, jobject key, jobject value) { + load_env(); + load_class_global_ref(&_c_MyMap, + "com/github/dart_lang/jnigen/generics/MyMap"); + if (_c_MyMap == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_MyMap, &_m_MyMap__put, "put", + "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); + if (_m_MyMap__put == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_MyMap__put, key, value); + return to_global_ref_result(_result); +} + +jmethodID _m_MyMap__entryStack = NULL; +FFI_PLUGIN_EXPORT +JniResult MyMap__entryStack(jobject self_) { + load_env(); + load_class_global_ref(&_c_MyMap, + "com/github/dart_lang/jnigen/generics/MyMap"); + if (_c_MyMap == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_MyMap, &_m_MyMap__entryStack, "entryStack", + "()Lcom/github/dart_lang/jnigen/generics/MyStack;"); + if (_m_MyMap__entryStack == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_MyMap__entryStack); + return to_global_ref_result(_result); +} + +// com.github.dart_lang.jnigen.generics.MyMap$MyEntry +jclass _c_MyMap_MyEntry = NULL; + +jmethodID _m_MyMap_MyEntry__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult MyMap_MyEntry__new0(jobject _parent, jobject key, jobject value) { + load_env(); + load_class_global_ref(&_c_MyMap_MyEntry, + "com/github/dart_lang/jnigen/generics/MyMap$MyEntry"); + if (_c_MyMap_MyEntry == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_MyMap_MyEntry, &_m_MyMap_MyEntry__new0, "", + "(Lcom/github/dart_lang/jnigen/generics/MyMap;Ljava/lang/" + "Object;Ljava/lang/Object;)V"); + if (_m_MyMap_MyEntry__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject( + jniEnv, _c_MyMap_MyEntry, _m_MyMap_MyEntry__new0, _parent, key, value); + return to_global_ref_result(_result); +} + +jfieldID _f_MyMap_MyEntry__key = NULL; +FFI_PLUGIN_EXPORT +JniResult get_MyMap_MyEntry__key(jobject self_) { + load_env(); + load_class_global_ref(&_c_MyMap_MyEntry, + "com/github/dart_lang/jnigen/generics/MyMap$MyEntry"); + if (_c_MyMap_MyEntry == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_MyMap_MyEntry, &_f_MyMap_MyEntry__key, "key", + "Ljava/lang/Object;"); + jobject _result = + (*jniEnv)->GetObjectField(jniEnv, self_, _f_MyMap_MyEntry__key); + return to_global_ref_result(_result); +} + +FFI_PLUGIN_EXPORT +JniResult set_MyMap_MyEntry__key(jobject self_, jobject value) { + load_env(); + load_class_global_ref(&_c_MyMap_MyEntry, + "com/github/dart_lang/jnigen/generics/MyMap$MyEntry"); + if (_c_MyMap_MyEntry == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_MyMap_MyEntry, &_f_MyMap_MyEntry__key, "key", + "Ljava/lang/Object;"); + (*jniEnv)->SetObjectField(jniEnv, self_, _f_MyMap_MyEntry__key, value); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jfieldID _f_MyMap_MyEntry__value = NULL; +FFI_PLUGIN_EXPORT +JniResult get_MyMap_MyEntry__value(jobject self_) { + load_env(); + load_class_global_ref(&_c_MyMap_MyEntry, + "com/github/dart_lang/jnigen/generics/MyMap$MyEntry"); + if (_c_MyMap_MyEntry == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_MyMap_MyEntry, &_f_MyMap_MyEntry__value, "value", + "Ljava/lang/Object;"); + jobject _result = + (*jniEnv)->GetObjectField(jniEnv, self_, _f_MyMap_MyEntry__value); + return to_global_ref_result(_result); +} + +FFI_PLUGIN_EXPORT +JniResult set_MyMap_MyEntry__value(jobject self_, jobject value) { + load_env(); + load_class_global_ref(&_c_MyMap_MyEntry, + "com/github/dart_lang/jnigen/generics/MyMap$MyEntry"); + if (_c_MyMap_MyEntry == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_MyMap_MyEntry, &_f_MyMap_MyEntry__value, "value", + "Ljava/lang/Object;"); + (*jniEnv)->SetObjectField(jniEnv, self_, _f_MyMap_MyEntry__value, value); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +// com.github.dart_lang.jnigen.generics.MyStack +jclass _c_MyStack = NULL; + +jmethodID _m_MyStack__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult MyStack__new0() { + load_env(); + load_class_global_ref(&_c_MyStack, + "com/github/dart_lang/jnigen/generics/MyStack"); + if (_c_MyStack == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_MyStack, &_m_MyStack__new0, "", "()V"); + if (_m_MyStack__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject(jniEnv, _c_MyStack, _m_MyStack__new0); + return to_global_ref_result(_result); +} + +jmethodID _m_MyStack__fromArray = NULL; +FFI_PLUGIN_EXPORT +JniResult MyStack__fromArray(jobject arr) { + load_env(); + load_class_global_ref(&_c_MyStack, + "com/github/dart_lang/jnigen/generics/MyStack"); + if (_c_MyStack == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method( + _c_MyStack, &_m_MyStack__fromArray, "fromArray", + "([Ljava/lang/Object;)Lcom/github/dart_lang/jnigen/generics/MyStack;"); + if (_m_MyStack__fromArray == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_MyStack, _m_MyStack__fromArray, arr); + return to_global_ref_result(_result); +} + +jmethodID _m_MyStack__fromArrayOfArrayOfGrandParents = NULL; +FFI_PLUGIN_EXPORT +JniResult MyStack__fromArrayOfArrayOfGrandParents(jobject arr) { + load_env(); + load_class_global_ref(&_c_MyStack, + "com/github/dart_lang/jnigen/generics/MyStack"); + if (_c_MyStack == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method( + _c_MyStack, &_m_MyStack__fromArrayOfArrayOfGrandParents, + "fromArrayOfArrayOfGrandParents", + "([[Lcom/github/dart_lang/jnigen/generics/GrandParent;)Lcom/github/" + "dart_lang/jnigen/generics/MyStack;"); + if (_m_MyStack__fromArrayOfArrayOfGrandParents == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_MyStack, _m_MyStack__fromArrayOfArrayOfGrandParents, arr); + return to_global_ref_result(_result); +} + +jmethodID _m_MyStack__of = NULL; +FFI_PLUGIN_EXPORT +JniResult MyStack__of() { + load_env(); + load_class_global_ref(&_c_MyStack, + "com/github/dart_lang/jnigen/generics/MyStack"); + if (_c_MyStack == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_MyStack, &_m_MyStack__of, "of", + "()Lcom/github/dart_lang/jnigen/generics/MyStack;"); + if (_m_MyStack__of == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallStaticObjectMethod(jniEnv, _c_MyStack, _m_MyStack__of); + return to_global_ref_result(_result); +} + +jmethodID _m_MyStack__of1 = NULL; +FFI_PLUGIN_EXPORT +JniResult MyStack__of1(jobject obj) { + load_env(); + load_class_global_ref(&_c_MyStack, + "com/github/dart_lang/jnigen/generics/MyStack"); + if (_c_MyStack == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method( + _c_MyStack, &_m_MyStack__of1, "of", + "(Ljava/lang/Object;)Lcom/github/dart_lang/jnigen/generics/MyStack;"); + if (_m_MyStack__of1 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod(jniEnv, _c_MyStack, + _m_MyStack__of1, obj); + return to_global_ref_result(_result); +} + +jmethodID _m_MyStack__of2 = NULL; +FFI_PLUGIN_EXPORT +JniResult MyStack__of2(jobject obj, jobject obj2) { + load_env(); + load_class_global_ref(&_c_MyStack, + "com/github/dart_lang/jnigen/generics/MyStack"); + if (_c_MyStack == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_MyStack, &_m_MyStack__of2, "of", + "(Ljava/lang/Object;Ljava/lang/Object;)Lcom/github/" + "dart_lang/jnigen/generics/MyStack;"); + if (_m_MyStack__of2 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_MyStack, _m_MyStack__of2, obj, obj2); + return to_global_ref_result(_result); +} + +jmethodID _m_MyStack__push = NULL; +FFI_PLUGIN_EXPORT +JniResult MyStack__push(jobject self_, jobject item) { + load_env(); + load_class_global_ref(&_c_MyStack, + "com/github/dart_lang/jnigen/generics/MyStack"); + if (_c_MyStack == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_MyStack, &_m_MyStack__push, "push", "(Ljava/lang/Object;)V"); + if (_m_MyStack__push == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_MyStack__push, item); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_MyStack__pop = NULL; +FFI_PLUGIN_EXPORT +JniResult MyStack__pop(jobject self_) { + load_env(); + load_class_global_ref(&_c_MyStack, + "com/github/dart_lang/jnigen/generics/MyStack"); + if (_c_MyStack == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_MyStack, &_m_MyStack__pop, "pop", "()Ljava/lang/Object;"); + if (_m_MyStack__pop == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_MyStack__pop); + return to_global_ref_result(_result); +} + +jmethodID _m_MyStack__size = NULL; +FFI_PLUGIN_EXPORT +JniResult MyStack__size(jobject self_) { + load_env(); + load_class_global_ref(&_c_MyStack, + "com/github/dart_lang/jnigen/generics/MyStack"); + if (_c_MyStack == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_MyStack, &_m_MyStack__size, "size", "()I"); + if (_m_MyStack__size == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int32_t _result = (*jniEnv)->CallIntMethod(jniEnv, self_, _m_MyStack__size); + return (JniResult){.value = {.i = _result}, .exception = check_exception()}; +} + +// com.github.dart_lang.jnigen.generics.StringKeyedMap +jclass _c_StringKeyedMap = NULL; + +jmethodID _m_StringKeyedMap__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult StringKeyedMap__new0() { + load_env(); + load_class_global_ref(&_c_StringKeyedMap, + "com/github/dart_lang/jnigen/generics/StringKeyedMap"); + if (_c_StringKeyedMap == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_StringKeyedMap, &_m_StringKeyedMap__new0, "", "()V"); + if (_m_StringKeyedMap__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->NewObject(jniEnv, _c_StringKeyedMap, _m_StringKeyedMap__new0); + return to_global_ref_result(_result); +} + +// com.github.dart_lang.jnigen.generics.StringMap +jclass _c_StringMap = NULL; + +jmethodID _m_StringMap__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult StringMap__new0() { + load_env(); + load_class_global_ref(&_c_StringMap, + "com/github/dart_lang/jnigen/generics/StringMap"); + if (_c_StringMap == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_StringMap, &_m_StringMap__new0, "", "()V"); + if (_m_StringMap__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->NewObject(jniEnv, _c_StringMap, _m_StringMap__new0); + return to_global_ref_result(_result); +} + +// com.github.dart_lang.jnigen.generics.StringStack +jclass _c_StringStack = NULL; + +jmethodID _m_StringStack__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult StringStack__new0() { + load_env(); + load_class_global_ref(&_c_StringStack, + "com/github/dart_lang/jnigen/generics/StringStack"); + if (_c_StringStack == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_StringStack, &_m_StringStack__new0, "", "()V"); + if (_m_StringStack__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->NewObject(jniEnv, _c_StringStack, _m_StringStack__new0); + return to_global_ref_result(_result); +} + +// com.github.dart_lang.jnigen.generics.StringValuedMap +jclass _c_StringValuedMap = NULL; + +jmethodID _m_StringValuedMap__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult StringValuedMap__new0() { + load_env(); + load_class_global_ref(&_c_StringValuedMap, + "com/github/dart_lang/jnigen/generics/StringValuedMap"); + if (_c_StringValuedMap == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_StringValuedMap, &_m_StringValuedMap__new0, "", "()V"); + if (_m_StringValuedMap__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject(jniEnv, _c_StringValuedMap, + _m_StringValuedMap__new0); + return to_global_ref_result(_result); +} + +// com.github.dart_lang.jnigen.interfaces.MyInterface +jclass _c_MyInterface = NULL; + +jmethodID _m_MyInterface__voidCallback = NULL; +FFI_PLUGIN_EXPORT +JniResult MyInterface__voidCallback(jobject self_, jobject s) { + load_env(); + load_class_global_ref(&_c_MyInterface, + "com/github/dart_lang/jnigen/interfaces/MyInterface"); + if (_c_MyInterface == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_MyInterface, &_m_MyInterface__voidCallback, "voidCallback", + "(Ljava/lang/String;)V"); + if (_m_MyInterface__voidCallback == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_MyInterface__voidCallback, s); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_MyInterface__stringCallback = NULL; +FFI_PLUGIN_EXPORT +JniResult MyInterface__stringCallback(jobject self_, jobject s) { + load_env(); + load_class_global_ref(&_c_MyInterface, + "com/github/dart_lang/jnigen/interfaces/MyInterface"); + if (_c_MyInterface == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_MyInterface, &_m_MyInterface__stringCallback, "stringCallback", + "(Ljava/lang/String;)Ljava/lang/String;"); + if (_m_MyInterface__stringCallback == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod( + jniEnv, self_, _m_MyInterface__stringCallback, s); + return to_global_ref_result(_result); +} + +jmethodID _m_MyInterface__varCallback = NULL; +FFI_PLUGIN_EXPORT +JniResult MyInterface__varCallback(jobject self_, jobject t) { + load_env(); + load_class_global_ref(&_c_MyInterface, + "com/github/dart_lang/jnigen/interfaces/MyInterface"); + if (_c_MyInterface == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_MyInterface, &_m_MyInterface__varCallback, "varCallback", + "(Ljava/lang/Object;)Ljava/lang/Object;"); + if (_m_MyInterface__varCallback == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallObjectMethod(jniEnv, self_, + _m_MyInterface__varCallback, t); + return to_global_ref_result(_result); +} + +jmethodID _m_MyInterface__manyPrimitives = NULL; +FFI_PLUGIN_EXPORT +JniResult MyInterface__manyPrimitives(jobject self_, + int32_t a, + uint8_t b, + uint16_t c, + double d) { + load_env(); + load_class_global_ref(&_c_MyInterface, + "com/github/dart_lang/jnigen/interfaces/MyInterface"); + if (_c_MyInterface == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_MyInterface, &_m_MyInterface__manyPrimitives, "manyPrimitives", + "(IZCD)J"); + if (_m_MyInterface__manyPrimitives == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + int64_t _result = (*jniEnv)->CallLongMethod( + jniEnv, self_, _m_MyInterface__manyPrimitives, a, b, c, d); + return (JniResult){.value = {.j = _result}, .exception = check_exception()}; +} + +// com.github.dart_lang.jnigen.interfaces.MyInterfaceConsumer +jclass _c_MyInterfaceConsumer = NULL; + +jmethodID _m_MyInterfaceConsumer__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult MyInterfaceConsumer__new0() { + load_env(); + load_class_global_ref( + &_c_MyInterfaceConsumer, + "com/github/dart_lang/jnigen/interfaces/MyInterfaceConsumer"); + if (_c_MyInterfaceConsumer == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_MyInterfaceConsumer, &_m_MyInterfaceConsumer__new0, "", + "()V"); + if (_m_MyInterfaceConsumer__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject(jniEnv, _c_MyInterfaceConsumer, + _m_MyInterfaceConsumer__new0); + return to_global_ref_result(_result); +} + +jmethodID _m_MyInterfaceConsumer__consumeOnAnotherThread = NULL; +FFI_PLUGIN_EXPORT +JniResult MyInterfaceConsumer__consumeOnAnotherThread(jobject myInterface, + jobject s, + int32_t a, + uint8_t b, + uint16_t c, + double d, + jobject t) { + load_env(); + load_class_global_ref( + &_c_MyInterfaceConsumer, + "com/github/dart_lang/jnigen/interfaces/MyInterfaceConsumer"); + if (_c_MyInterfaceConsumer == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_MyInterfaceConsumer, + &_m_MyInterfaceConsumer__consumeOnAnotherThread, + "consumeOnAnotherThread", + "(Lcom/github/dart_lang/jnigen/interfaces/" + "MyInterface;Ljava/lang/String;IZCDLjava/lang/Object;)V"); + if (_m_MyInterfaceConsumer__consumeOnAnotherThread == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallStaticVoidMethod( + jniEnv, _c_MyInterfaceConsumer, + _m_MyInterfaceConsumer__consumeOnAnotherThread, myInterface, s, a, b, c, + d, t); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_MyInterfaceConsumer__consumeOnSameThread = NULL; +FFI_PLUGIN_EXPORT +JniResult MyInterfaceConsumer__consumeOnSameThread(jobject myInterface, + jobject s, + int32_t a, + uint8_t b, + uint16_t c, + double d, + jobject t) { + load_env(); + load_class_global_ref( + &_c_MyInterfaceConsumer, + "com/github/dart_lang/jnigen/interfaces/MyInterfaceConsumer"); + if (_c_MyInterfaceConsumer == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_MyInterfaceConsumer, + &_m_MyInterfaceConsumer__consumeOnSameThread, + "consumeOnSameThread", + "(Lcom/github/dart_lang/jnigen/interfaces/" + "MyInterface;Ljava/lang/String;IZCDLjava/lang/Object;)V"); + if (_m_MyInterfaceConsumer__consumeOnSameThread == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallStaticVoidMethod(jniEnv, _c_MyInterfaceConsumer, + _m_MyInterfaceConsumer__consumeOnSameThread, + myInterface, s, a, b, c, d, t); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +// com.github.dart_lang.jnigen.interfaces.MyRunnable +jclass _c_MyRunnable = NULL; + +jmethodID _m_MyRunnable__run = NULL; +FFI_PLUGIN_EXPORT +JniResult MyRunnable__run(jobject self_) { + load_env(); + load_class_global_ref(&_c_MyRunnable, + "com/github/dart_lang/jnigen/interfaces/MyRunnable"); + if (_c_MyRunnable == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_MyRunnable, &_m_MyRunnable__run, "run", "()V"); + if (_m_MyRunnable__run == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_MyRunnable__run); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +// com.github.dart_lang.jnigen.interfaces.MyRunnableRunner +jclass _c_MyRunnableRunner = NULL; + +jmethodID _m_MyRunnableRunner__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult MyRunnableRunner__new0(jobject runnable) { + load_env(); + load_class_global_ref( + &_c_MyRunnableRunner, + "com/github/dart_lang/jnigen/interfaces/MyRunnableRunner"); + if (_c_MyRunnableRunner == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_MyRunnableRunner, &_m_MyRunnableRunner__new0, "", + "(Lcom/github/dart_lang/jnigen/interfaces/MyRunnable;)V"); + if (_m_MyRunnableRunner__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject(jniEnv, _c_MyRunnableRunner, + _m_MyRunnableRunner__new0, runnable); + return to_global_ref_result(_result); +} + +jmethodID _m_MyRunnableRunner__runOnSameThread = NULL; +FFI_PLUGIN_EXPORT +JniResult MyRunnableRunner__runOnSameThread(jobject self_) { + load_env(); + load_class_global_ref( + &_c_MyRunnableRunner, + "com/github/dart_lang/jnigen/interfaces/MyRunnableRunner"); + if (_c_MyRunnableRunner == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_MyRunnableRunner, &_m_MyRunnableRunner__runOnSameThread, + "runOnSameThread", "()V"); + if (_m_MyRunnableRunner__runOnSameThread == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, + _m_MyRunnableRunner__runOnSameThread); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_MyRunnableRunner__runOnAnotherThread = NULL; +FFI_PLUGIN_EXPORT +JniResult MyRunnableRunner__runOnAnotherThread(jobject self_) { + load_env(); + load_class_global_ref( + &_c_MyRunnableRunner, + "com/github/dart_lang/jnigen/interfaces/MyRunnableRunner"); + if (_c_MyRunnableRunner == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_MyRunnableRunner, &_m_MyRunnableRunner__runOnAnotherThread, + "runOnAnotherThread", "()V"); + if (_m_MyRunnableRunner__runOnAnotherThread == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, + _m_MyRunnableRunner__runOnAnotherThread); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jfieldID _f_MyRunnableRunner__error = NULL; +FFI_PLUGIN_EXPORT +JniResult get_MyRunnableRunner__error(jobject self_) { + load_env(); + load_class_global_ref( + &_c_MyRunnableRunner, + "com/github/dart_lang/jnigen/interfaces/MyRunnableRunner"); + if (_c_MyRunnableRunner == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_MyRunnableRunner, &_f_MyRunnableRunner__error, "error", + "Ljava/lang/Throwable;"); + jobject _result = + (*jniEnv)->GetObjectField(jniEnv, self_, _f_MyRunnableRunner__error); + return to_global_ref_result(_result); +} + +FFI_PLUGIN_EXPORT +JniResult set_MyRunnableRunner__error(jobject self_, jobject value) { + load_env(); + load_class_global_ref( + &_c_MyRunnableRunner, + "com/github/dart_lang/jnigen/interfaces/MyRunnableRunner"); + if (_c_MyRunnableRunner == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_MyRunnableRunner, &_f_MyRunnableRunner__error, "error", + "Ljava/lang/Throwable;"); + (*jniEnv)->SetObjectField(jniEnv, self_, _f_MyRunnableRunner__error, value); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +// com.github.dart_lang.jnigen.annotations.JsonSerializable$Case +jclass _c_JsonSerializable_Case = NULL; + +jmethodID _m_JsonSerializable_Case__values = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonSerializable_Case__values() { + load_env(); + load_class_global_ref( + &_c_JsonSerializable_Case, + "com/github/dart_lang/jnigen/annotations/JsonSerializable$Case"); + if (_c_JsonSerializable_Case == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method( + _c_JsonSerializable_Case, &_m_JsonSerializable_Case__values, "values", + "()[Lcom/github/dart_lang/jnigen/annotations/JsonSerializable$Case;"); + if (_m_JsonSerializable_Case__values == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_JsonSerializable_Case, _m_JsonSerializable_Case__values); + return to_global_ref_result(_result); +} + +jmethodID _m_JsonSerializable_Case__valueOf = NULL; +FFI_PLUGIN_EXPORT +JniResult JsonSerializable_Case__valueOf(jobject name) { + load_env(); + load_class_global_ref( + &_c_JsonSerializable_Case, + "com/github/dart_lang/jnigen/annotations/JsonSerializable$Case"); + if (_c_JsonSerializable_Case == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_JsonSerializable_Case, + &_m_JsonSerializable_Case__valueOf, "valueOf", + "(Ljava/lang/String;)Lcom/github/dart_lang/jnigen/" + "annotations/JsonSerializable$Case;"); + if (_m_JsonSerializable_Case__valueOf == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_JsonSerializable_Case, _m_JsonSerializable_Case__valueOf, + name); + return to_global_ref_result(_result); +} + +// com.github.dart_lang.jnigen.annotations.MyDataClass +jclass _c_MyDataClass = NULL; + +jmethodID _m_MyDataClass__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult MyDataClass__new0() { + load_env(); + load_class_global_ref(&_c_MyDataClass, + "com/github/dart_lang/jnigen/annotations/MyDataClass"); + if (_c_MyDataClass == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_MyDataClass, &_m_MyDataClass__new0, "", "()V"); + if (_m_MyDataClass__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->NewObject(jniEnv, _c_MyDataClass, _m_MyDataClass__new0); + return to_global_ref_result(_result); +} diff --git a/pkgs/jnigen/test/simple_package_test/c_based/dart_bindings/simple_package.dart b/pkgs/jnigen/test/simple_package_test/c_based/dart_bindings/simple_package.dart new file mode 100644 index 000000000..c4f64a18c --- /dev/null +++ b/pkgs/jnigen/test/simple_package_test/c_based/dart_bindings/simple_package.dart @@ -0,0 +1,3998 @@ +// 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. + +// Autogenerated by jnigen. DO NOT EDIT! + +// ignore_for_file: annotate_overrides +// ignore_for_file: camel_case_extensions +// ignore_for_file: camel_case_types +// ignore_for_file: constant_identifier_names +// ignore_for_file: file_names +// ignore_for_file: lines_longer_than_80_chars +// ignore_for_file: no_leading_underscores_for_local_identifiers +// ignore_for_file: non_constant_identifier_names +// ignore_for_file: overridden_fields +// ignore_for_file: unnecessary_cast +// ignore_for_file: unused_element +// ignore_for_file: unused_field +// ignore_for_file: unused_import +// ignore_for_file: unused_local_variable +// ignore_for_file: unused_shown_name + +import "dart:isolate" show ReceivePort; +import "dart:ffi" as ffi; +import "package:jni/internal_helpers_for_jnigen.dart"; +import "package:jni/jni.dart" as jni; + +// Auto-generated initialization code. + +final ffi.Pointer Function(String sym) jniLookup = + ProtectedJniExtensions.initGeneratedLibrary("simple_package"); + +/// from: com.github.dart_lang.jnigen.simple_package.Color +class Color extends jni.JObject { + @override + late final jni.JObjType $type = type; + + Color.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $ColorType(); + static final _values = + jniLookup>("Color__values") + .asFunction(); + + /// from: static public com.github.dart_lang.jnigen.simple_package.Color[] values() + /// The returned object must be released after use, by calling the [release] method. + static jni.JArray values() { + return const jni.JArrayType($ColorType()).fromRef(_values().object); + } + + static final _valueOf = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer)>>("Color__valueOf") + .asFunction)>(); + + /// from: static public com.github.dart_lang.jnigen.simple_package.Color valueOf(java.lang.String name) + /// The returned object must be released after use, by calling the [release] method. + static Color valueOf( + jni.JString name, + ) { + return const $ColorType().fromRef(_valueOf(name.reference).object); + } +} + +final class $ColorType extends jni.JObjType { + const $ColorType(); + + @override + String get signature => r"Lcom/github/dart_lang/jnigen/simple_package/Color;"; + + @override + Color fromRef(jni.JObjectPtr ref) => Color.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($ColorType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($ColorType) && other is $ColorType; + } +} + +/// from: com.github.dart_lang.jnigen.simple_package.Example +class Example extends jni.JObject { + @override + late final jni.JObjType $type = type; + + Example.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $ExampleType(); + + /// from: static public final int ON + static const ON = 1; + + /// from: static public final int OFF + static const OFF = 0; + + /// from: static public final double PI + static const PI = 3.14159; + + /// from: static public final char SEMICOLON + static const SEMICOLON = 59; + + /// from: static public final java.lang.String SEMICOLON_STRING + static const SEMICOLON_STRING = r""";"""; + + static final _get_unusedRandom = + jniLookup>( + "get_Example__unusedRandom") + .asFunction(); + + /// from: static public final java.util.Random unusedRandom + /// The returned object must be released after use, by calling the [release] method. + static jni.JObject get unusedRandom => + const jni.JObjectType().fromRef(_get_unusedRandom().object); + + static final _get_protectedField = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>>("get_Example__protectedField") + .asFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>(); + + static final _set_protectedField = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(jni.JObjectPtr, + ffi.Pointer)>>("set_Example__protectedField") + .asFunction< + jni.JniResult Function(jni.JObjectPtr, ffi.Pointer)>(); + + /// from: protected java.util.Random protectedField + /// The returned object must be released after use, by calling the [release] method. + jni.JObject get protectedField => + const jni.JObjectType().fromRef(_get_protectedField(reference).object); + + /// from: protected java.util.Random protectedField + /// The returned object must be released after use, by calling the [release] method. + set protectedField(jni.JObject value) => + _set_protectedField(reference, value.reference).check(); + + static final _getAmount = + jniLookup>( + "Example__getAmount") + .asFunction(); + + /// from: static public int getAmount() + static int getAmount() { + return _getAmount().integer; + } + + static final _getPi = + jniLookup>("Example__getPi") + .asFunction(); + + /// from: static public double getPi() + static double getPi() { + return _getPi().doubleFloat; + } + + static final _getAsterisk = + jniLookup>( + "Example__getAsterisk") + .asFunction(); + + /// from: static public char getAsterisk() + static int getAsterisk() { + return _getAsterisk().char; + } + + static final _getName = + jniLookup>( + "Example__getName") + .asFunction(); + + /// from: static public java.lang.String getName() + /// The returned object must be released after use, by calling the [release] method. + static jni.JString getName() { + return const jni.JStringType().fromRef(_getName().object); + } + + static final _getNestedInstance = + jniLookup>( + "Example__getNestedInstance") + .asFunction(); + + /// from: static public com.github.dart_lang.jnigen.simple_package.Example.Nested getNestedInstance() + /// The returned object must be released after use, by calling the [release] method. + static Example_Nested getNestedInstance() { + return const $Example_NestedType().fromRef(_getNestedInstance().object); + } + + static final _setAmount = + jniLookup>( + "Example__setAmount") + .asFunction(); + + /// from: static public void setAmount(int newAmount) + static void setAmount( + int newAmount, + ) { + return _setAmount(newAmount).check(); + } + + static final _setName = jniLookup< + ffi + .NativeFunction)>>( + "Example__setName") + .asFunction)>(); + + /// from: static public void setName(java.lang.String newName) + static void setName( + jni.JString newName, + ) { + return _setName(newName.reference).check(); + } + + static final _setNestedInstance = jniLookup< + ffi + .NativeFunction)>>( + "Example__setNestedInstance") + .asFunction)>(); + + /// from: static public void setNestedInstance(com.github.dart_lang.jnigen.simple_package.Example.Nested newNested) + static void setNestedInstance( + Example_Nested newNested, + ) { + return _setNestedInstance(newNested.reference).check(); + } + + static final _max4 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Int32, ffi.Int32, ffi.Int32, ffi.Int32)>>("Example__max4") + .asFunction(); + + /// from: static public int max4(int a, int b, int c, int d) + static int max4( + int a, + int b, + int c, + int d, + ) { + return _max4(a, b, c, d).integer; + } + + static final _max8 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Int32, ffi.Int32, ffi.Int32, ffi.Int32, + ffi.Int32, ffi.Int32, ffi.Int32, ffi.Int32)>>("Example__max8") + .asFunction< + jni.JniResult Function(int, int, int, int, int, int, int, int)>(); + + /// from: static public int max8(int a, int b, int c, int d, int e, int f, int g, int h) + static int max8( + int a, + int b, + int c, + int d, + int e, + int f, + int g, + int h, + ) { + return _max8(a, b, c, d, e, f, g, h).integer; + } + + static final _getNumber = jniLookup< + ffi + .NativeFunction)>>( + "Example__getNumber") + .asFunction)>(); + + /// from: public int getNumber() + int getNumber() { + return _getNumber(reference).integer; + } + + static final _setNumber = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Int32)>>("Example__setNumber") + .asFunction, int)>(); + + /// from: public void setNumber(int number) + void setNumber( + int number, + ) { + return _setNumber(reference, number).check(); + } + + static final _getIsUp = jniLookup< + ffi + .NativeFunction)>>( + "Example__getIsUp") + .asFunction)>(); + + /// from: public boolean getIsUp() + bool getIsUp() { + return _getIsUp(reference).boolean; + } + + static final _setUp = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Uint8)>>("Example__setUp") + .asFunction, int)>(); + + /// from: public void setUp(boolean isUp) + void setUp( + bool isUp, + ) { + return _setUp(reference, isUp ? 1 : 0).check(); + } + + static final _getCodename = jniLookup< + ffi + .NativeFunction)>>( + "Example__getCodename") + .asFunction)>(); + + /// from: public java.lang.String getCodename() + /// The returned object must be released after use, by calling the [release] method. + jni.JString getCodename() { + return const jni.JStringType().fromRef(_getCodename(reference).object); + } + + static final _setCodename = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("Example__setCodename") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void setCodename(java.lang.String codename) + void setCodename( + jni.JString codename, + ) { + return _setCodename(reference, codename.reference).check(); + } + + static final _getRandom = jniLookup< + ffi + .NativeFunction)>>( + "Example__getRandom") + .asFunction)>(); + + /// from: public java.util.Random getRandom() + /// The returned object must be released after use, by calling the [release] method. + jni.JObject getRandom() { + return const jni.JObjectType().fromRef(_getRandom(reference).object); + } + + static final _setRandom = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("Example__setRandom") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void setRandom(java.util.Random random) + void setRandom( + jni.JObject random, + ) { + return _setRandom(reference, random.reference).check(); + } + + static final _getRandomLong = jniLookup< + ffi + .NativeFunction)>>( + "Example__getRandomLong") + .asFunction)>(); + + /// from: public long getRandomLong() + int getRandomLong() { + return _getRandomLong(reference).long; + } + + static final _add4Longs = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, ffi.Int64, + ffi.Int64, ffi.Int64, ffi.Int64)>>("Example__add4Longs") + .asFunction< + jni.JniResult Function(ffi.Pointer, int, int, int, int)>(); + + /// from: public long add4Longs(long a, long b, long c, long d) + int add4Longs( + int a, + int b, + int c, + int d, + ) { + return _add4Longs(reference, a, b, c, d).long; + } + + static final _add8Longs = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Int64, + ffi.Int64, + ffi.Int64, + ffi.Int64, + ffi.Int64, + ffi.Int64, + ffi.Int64, + ffi.Int64)>>("Example__add8Longs") + .asFunction< + jni.JniResult Function( + ffi.Pointer, int, int, int, int, int, int, int, int)>(); + + /// from: public long add8Longs(long a, long b, long c, long d, long e, long f, long g, long h) + int add8Longs( + int a, + int b, + int c, + int d, + int e, + int f, + int g, + int h, + ) { + return _add8Longs(reference, a, b, c, d, e, f, g, h).long; + } + + static final _getRandomNumericString = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("Example__getRandomNumericString") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public java.lang.String getRandomNumericString(java.util.Random random) + /// The returned object must be released after use, by calling the [release] method. + jni.JString getRandomNumericString( + jni.JObject random, + ) { + return const jni.JStringType() + .fromRef(_getRandomNumericString(reference, random.reference).object); + } + + static final _protectedMethod = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>("Example__protectedMethod") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); + + /// from: protected void protectedMethod(java.lang.String a, java.lang.String b) + void protectedMethod( + jni.JString a, + jni.JString b, + ) { + return _protectedMethod(reference, a.reference, b.reference).check(); + } + + static final _finalMethod = jniLookup< + ffi + .NativeFunction)>>( + "Example__finalMethod") + .asFunction)>(); + + /// from: public final void finalMethod() + void finalMethod() { + return _finalMethod(reference).check(); + } + + static final _getList = jniLookup< + ffi + .NativeFunction)>>( + "Example__getList") + .asFunction)>(); + + /// from: public java.util.List getList() + /// The returned object must be released after use, by calling the [release] method. + jni.JList getList() { + return const jni.JListType(jni.JStringType()) + .fromRef(_getList(reference).object); + } + + static final _joinStrings = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>("Example__joinStrings") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); + + /// from: public java.lang.String joinStrings(java.util.List values, java.lang.String delim) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Joins the strings in the list using the given delimiter. + jni.JString joinStrings( + jni.JList values, + jni.JString delim, + ) { + return const jni.JStringType().fromRef( + _joinStrings(reference, values.reference, delim.reference).object); + } + + static final _methodWithSeveralParams = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Uint16, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>("Example__methodWithSeveralParams") + .asFunction< + jni.JniResult Function( + ffi.Pointer, + int, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>(); + + /// from: public void methodWithSeveralParams(char ch, java.lang.String s, int[] a, T t, java.util.List lt, java.util.Map wm) + void methodWithSeveralParams<$T extends jni.JObject>( + int ch, + jni.JString s, + jni.JArray a, + $T t, + jni.JList<$T> lt, + jni.JMap wm, { + jni.JObjType<$T>? T, + }) { + T ??= jni.lowestCommonSuperType([ + (lt.$type as jni.JListType).E, + t.$type, + ]) as jni.JObjType<$T>; + return _methodWithSeveralParams(reference, ch, s.reference, a.reference, + t.reference, lt.reference, wm.reference) + .check(); + } + + static final _new0 = + jniLookup>("Example__new0") + .asFunction(); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory Example() { + return Example.fromRef(_new0().object); + } + + static final _new1 = + jniLookup>( + "Example__new1") + .asFunction(); + + /// from: public void (int number) + /// The returned object must be released after use, by calling the [release] method. + factory Example.new1( + int number, + ) { + return Example.fromRef(_new1(number).object); + } + + static final _new2 = jniLookup< + ffi.NativeFunction>( + "Example__new2") + .asFunction(); + + /// from: public void (int number, boolean isUp) + /// The returned object must be released after use, by calling the [release] method. + factory Example.new2( + int number, + bool isUp, + ) { + return Example.fromRef(_new2(number, isUp ? 1 : 0).object); + } + + static final _new3 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Int32, ffi.Uint8, + ffi.Pointer)>>("Example__new3") + .asFunction)>(); + + /// from: public void (int number, boolean isUp, java.lang.String codename) + /// The returned object must be released after use, by calling the [release] method. + factory Example.new3( + int number, + bool isUp, + jni.JString codename, + ) { + return Example.fromRef( + _new3(number, isUp ? 1 : 0, codename.reference).object); + } + + static final _new4 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Int32, ffi.Int32, ffi.Int32, ffi.Int32, + ffi.Int32, ffi.Int32, ffi.Int32, ffi.Int32)>>("Example__new4") + .asFunction< + jni.JniResult Function(int, int, int, int, int, int, int, int)>(); + + /// from: public void (int a, int b, int c, int d, int e, int f, int g, int h) + /// The returned object must be released after use, by calling the [release] method. + factory Example.new4( + int a, + int b, + int c, + int d, + int e, + int f, + int g, + int h, + ) { + return Example.fromRef(_new4(a, b, c, d, e, f, g, h).object); + } + + static final _whichExample = jniLookup< + ffi + .NativeFunction)>>( + "Example__whichExample") + .asFunction)>(); + + /// from: public int whichExample() + int whichExample() { + return _whichExample(reference).integer; + } + + static final _addInts = jniLookup< + ffi.NativeFunction>( + "Example__addInts") + .asFunction(); + + /// from: static public int addInts(int a, int b) + static int addInts( + int a, + int b, + ) { + return _addInts(a, b).integer; + } + + static final _getArr = + jniLookup>("Example__getArr") + .asFunction(); + + /// from: static public int[] getArr() + /// The returned object must be released after use, by calling the [release] method. + static jni.JArray getArr() { + return const jni.JArrayType(jni.jintType()).fromRef(_getArr().object); + } + + static final _addAll = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer)>>("Example__addAll") + .asFunction)>(); + + /// from: static public int addAll(int[] arr) + static int addAll( + jni.JArray arr, + ) { + return _addAll(arr.reference).integer; + } + + static final _getSelf = jniLookup< + ffi + .NativeFunction)>>( + "Example__getSelf") + .asFunction)>(); + + /// from: public com.github.dart_lang.jnigen.simple_package.Example getSelf() + /// The returned object must be released after use, by calling the [release] method. + Example getSelf() { + return const $ExampleType().fromRef(_getSelf(reference).object); + } + + static final _throwException = + jniLookup>( + "Example__throwException") + .asFunction(); + + /// from: static public void throwException() + static void throwException() { + return _throwException().check(); + } + + static final _overloaded = jniLookup< + ffi + .NativeFunction)>>( + "Example__overloaded") + .asFunction)>(); + + /// from: public void overloaded() + void overloaded() { + return _overloaded(reference).check(); + } + + static final _overloaded1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, ffi.Int32, + ffi.Pointer)>>("Example__overloaded1") + .asFunction< + jni.JniResult Function( + ffi.Pointer, int, ffi.Pointer)>(); + + /// from: public void overloaded(int a, java.lang.String b) + void overloaded1( + int a, + jni.JString b, + ) { + return _overloaded1(reference, a, b.reference).check(); + } + + static final _overloaded2 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Int32)>>("Example__overloaded2") + .asFunction, int)>(); + + /// from: public void overloaded(int a) + void overloaded2( + int a, + ) { + return _overloaded2(reference, a).check(); + } + + static final _overloaded3 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>("Example__overloaded3") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); + + /// from: public void overloaded(java.util.List a, java.lang.String b) + void overloaded3( + jni.JList a, + jni.JString b, + ) { + return _overloaded3(reference, a.reference, b.reference).check(); + } + + static final _overloaded4 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("Example__overloaded4") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void overloaded(java.util.List a) + void overloaded4( + jni.JList a, + ) { + return _overloaded4(reference, a.reference).check(); + } +} + +final class $ExampleType extends jni.JObjType { + const $ExampleType(); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/simple_package/Example;"; + + @override + Example fromRef(jni.JObjectPtr ref) => Example.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($ExampleType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($ExampleType) && other is $ExampleType; + } +} + +/// from: com.github.dart_lang.jnigen.simple_package.Example$Nested +class Example_Nested extends jni.JObject { + @override + late final jni.JObjType $type = type; + + Example_Nested.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $Example_NestedType(); + static final _new0 = + jniLookup>( + "Example_Nested__new0") + .asFunction(); + + /// from: public void (boolean value) + /// The returned object must be released after use, by calling the [release] method. + factory Example_Nested( + bool value, + ) { + return Example_Nested.fromRef(_new0(value ? 1 : 0).object); + } + + static final _usesAnonymousInnerClass = jniLookup< + ffi + .NativeFunction)>>( + "Example_Nested__usesAnonymousInnerClass") + .asFunction)>(); + + /// from: public void usesAnonymousInnerClass() + void usesAnonymousInnerClass() { + return _usesAnonymousInnerClass(reference).check(); + } + + static final _getValue = jniLookup< + ffi + .NativeFunction)>>( + "Example_Nested__getValue") + .asFunction)>(); + + /// from: public boolean getValue() + bool getValue() { + return _getValue(reference).boolean; + } + + static final _setValue = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Uint8)>>("Example_Nested__setValue") + .asFunction, int)>(); + + /// from: public void setValue(boolean value) + void setValue( + bool value, + ) { + return _setValue(reference, value ? 1 : 0).check(); + } +} + +final class $Example_NestedType extends jni.JObjType { + const $Example_NestedType(); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/simple_package/Example$Nested;"; + + @override + Example_Nested fromRef(jni.JObjectPtr ref) => Example_Nested.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($Example_NestedType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($Example_NestedType) && + other is $Example_NestedType; + } +} + +/// from: com.github.dart_lang.jnigen.simple_package.Example$Nested$NestedTwice +class Example_Nested_NestedTwice extends jni.JObject { + @override + late final jni.JObjType $type = type; + + Example_Nested_NestedTwice.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $Example_Nested_NestedTwiceType(); + static final _get_ZERO = + jniLookup>( + "get_Example_Nested_NestedTwice__ZERO") + .asFunction(); + + static final _set_ZERO = + jniLookup>( + "set_Example_Nested_NestedTwice__ZERO") + .asFunction(); + + /// from: static public int ZERO + static int get ZERO => _get_ZERO().integer; + + /// from: static public int ZERO + static set ZERO(int value) => _set_ZERO(value).check(); + + static final _new0 = jniLookup>( + "Example_Nested_NestedTwice__new0") + .asFunction(); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory Example_Nested_NestedTwice() { + return Example_Nested_NestedTwice.fromRef(_new0().object); + } +} + +final class $Example_Nested_NestedTwiceType + extends jni.JObjType { + const $Example_Nested_NestedTwiceType(); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/simple_package/Example$Nested$NestedTwice;"; + + @override + Example_Nested_NestedTwice fromRef(jni.JObjectPtr ref) => + Example_Nested_NestedTwice.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($Example_Nested_NestedTwiceType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($Example_Nested_NestedTwiceType) && + other is $Example_Nested_NestedTwiceType; + } +} + +/// from: com.github.dart_lang.jnigen.simple_package.Example$NonStaticNested +class Example_NonStaticNested extends jni.JObject { + @override + late final jni.JObjType $type = type; + + Example_NonStaticNested.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $Example_NonStaticNestedType(); + static final _get_ok = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>>("get_Example_NonStaticNested__ok") + .asFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>(); + + static final _set_ok = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(jni.JObjectPtr, + ffi.Uint8)>>("set_Example_NonStaticNested__ok") + .asFunction(); + + /// from: public boolean ok + bool get ok => _get_ok(reference).boolean; + + /// from: public boolean ok + set ok(bool value) => _set_ok(reference, value ? 1 : 0).check(); + + static final _new0 = jniLookup< + ffi + .NativeFunction)>>( + "Example_NonStaticNested__new0") + .asFunction)>(); + + /// from: public void (com.github.dart_lang.jnigen.simple_package.Example $parent) + /// The returned object must be released after use, by calling the [release] method. + factory Example_NonStaticNested( + Example $parent, + ) { + return Example_NonStaticNested.fromRef(_new0($parent.reference).object); + } +} + +final class $Example_NonStaticNestedType + extends jni.JObjType { + const $Example_NonStaticNestedType(); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/simple_package/Example$NonStaticNested;"; + + @override + Example_NonStaticNested fromRef(jni.JObjectPtr ref) => + Example_NonStaticNested.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($Example_NonStaticNestedType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($Example_NonStaticNestedType) && + other is $Example_NonStaticNestedType; + } +} + +/// from: com.github.dart_lang.jnigen.simple_package.Exceptions +class Exceptions extends jni.JObject { + @override + late final jni.JObjType $type = type; + + Exceptions.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $ExceptionsType(); + static final _new0 = jniLookup>( + "Exceptions__new0") + .asFunction(); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory Exceptions() { + return Exceptions.fromRef(_new0().object); + } + + static final _new1 = + jniLookup>( + "Exceptions__new1") + .asFunction(); + + /// from: public void (float x) + /// The returned object must be released after use, by calling the [release] method. + factory Exceptions.new1( + double x, + ) { + return Exceptions.fromRef(_new1(x).object); + } + + static final _new2 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Int32, ffi.Int32, ffi.Int32, ffi.Int32, + ffi.Int32, ffi.Int32)>>("Exceptions__new2") + .asFunction(); + + /// from: public void (int a, int b, int c, int d, int e, int f) + /// The returned object must be released after use, by calling the [release] method. + factory Exceptions.new2( + int a, + int b, + int c, + int d, + int e, + int f, + ) { + return Exceptions.fromRef(_new2(a, b, c, d, e, f).object); + } + + static final _staticObjectMethod = + jniLookup>( + "Exceptions__staticObjectMethod") + .asFunction(); + + /// from: static public java.lang.Object staticObjectMethod() + /// The returned object must be released after use, by calling the [release] method. + static jni.JObject staticObjectMethod() { + return const jni.JObjectType().fromRef(_staticObjectMethod().object); + } + + static final _staticIntMethod = + jniLookup>( + "Exceptions__staticIntMethod") + .asFunction(); + + /// from: static public int staticIntMethod() + static int staticIntMethod() { + return _staticIntMethod().integer; + } + + static final _staticObjectArrayMethod = + jniLookup>( + "Exceptions__staticObjectArrayMethod") + .asFunction(); + + /// from: static public java.lang.Object[] staticObjectArrayMethod() + /// The returned object must be released after use, by calling the [release] method. + static jni.JArray staticObjectArrayMethod() { + return const jni.JArrayType(jni.JObjectType()) + .fromRef(_staticObjectArrayMethod().object); + } + + static final _staticIntArrayMethod = + jniLookup>( + "Exceptions__staticIntArrayMethod") + .asFunction(); + + /// from: static public int[] staticIntArrayMethod() + /// The returned object must be released after use, by calling the [release] method. + static jni.JArray staticIntArrayMethod() { + return const jni.JArrayType(jni.jintType()) + .fromRef(_staticIntArrayMethod().object); + } + + static final _objectMethod = jniLookup< + ffi + .NativeFunction)>>( + "Exceptions__objectMethod") + .asFunction)>(); + + /// from: public java.lang.Object objectMethod() + /// The returned object must be released after use, by calling the [release] method. + jni.JObject objectMethod() { + return const jni.JObjectType().fromRef(_objectMethod(reference).object); + } + + static final _intMethod = jniLookup< + ffi + .NativeFunction)>>( + "Exceptions__intMethod") + .asFunction)>(); + + /// from: public int intMethod() + int intMethod() { + return _intMethod(reference).integer; + } + + static final _objectArrayMethod = jniLookup< + ffi + .NativeFunction)>>( + "Exceptions__objectArrayMethod") + .asFunction)>(); + + /// from: public java.lang.Object[] objectArrayMethod() + /// The returned object must be released after use, by calling the [release] method. + jni.JArray objectArrayMethod() { + return const jni.JArrayType(jni.JObjectType()) + .fromRef(_objectArrayMethod(reference).object); + } + + static final _intArrayMethod = jniLookup< + ffi + .NativeFunction)>>( + "Exceptions__intArrayMethod") + .asFunction)>(); + + /// from: public int[] intArrayMethod() + /// The returned object must be released after use, by calling the [release] method. + jni.JArray intArrayMethod() { + return const jni.JArrayType(jni.jintType()) + .fromRef(_intArrayMethod(reference).object); + } + + static final _throwNullPointerException = jniLookup< + ffi + .NativeFunction)>>( + "Exceptions__throwNullPointerException") + .asFunction)>(); + + /// from: public int throwNullPointerException() + int throwNullPointerException() { + return _throwNullPointerException(reference).integer; + } + + static final _throwFileNotFoundException = jniLookup< + ffi + .NativeFunction)>>( + "Exceptions__throwFileNotFoundException") + .asFunction)>(); + + /// from: public java.io.InputStream throwFileNotFoundException() + /// The returned object must be released after use, by calling the [release] method. + jni.JObject throwFileNotFoundException() { + return const jni.JObjectType() + .fromRef(_throwFileNotFoundException(reference).object); + } + + static final _throwClassCastException = jniLookup< + ffi + .NativeFunction)>>( + "Exceptions__throwClassCastException") + .asFunction)>(); + + /// from: public java.io.FileInputStream throwClassCastException() + /// The returned object must be released after use, by calling the [release] method. + jni.JObject throwClassCastException() { + return const jni.JObjectType() + .fromRef(_throwClassCastException(reference).object); + } + + static final _throwArrayIndexException = jniLookup< + ffi + .NativeFunction)>>( + "Exceptions__throwArrayIndexException") + .asFunction)>(); + + /// from: public int throwArrayIndexException() + int throwArrayIndexException() { + return _throwArrayIndexException(reference).integer; + } + + static final _throwArithmeticException = jniLookup< + ffi + .NativeFunction)>>( + "Exceptions__throwArithmeticException") + .asFunction)>(); + + /// from: public int throwArithmeticException() + int throwArithmeticException() { + return _throwArithmeticException(reference).integer; + } + + static final _throwLoremIpsum = + jniLookup>( + "Exceptions__throwLoremIpsum") + .asFunction(); + + /// from: static public void throwLoremIpsum() + static void throwLoremIpsum() { + return _throwLoremIpsum().check(); + } +} + +final class $ExceptionsType extends jni.JObjType { + const $ExceptionsType(); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/simple_package/Exceptions;"; + + @override + Exceptions fromRef(jni.JObjectPtr ref) => Exceptions.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($ExceptionsType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($ExceptionsType) && other is $ExceptionsType; + } +} + +/// from: com.github.dart_lang.jnigen.simple_package.Fields +class Fields extends jni.JObject { + @override + late final jni.JObjType $type = type; + + Fields.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $FieldsType(); + static final _get_amount = + jniLookup>( + "get_Fields__amount") + .asFunction(); + + static final _set_amount = + jniLookup>( + "set_Fields__amount") + .asFunction(); + + /// from: static public int amount + static int get amount => _get_amount().integer; + + /// from: static public int amount + static set amount(int value) => _set_amount(value).check(); + + static final _get_pi = + jniLookup>("get_Fields__pi") + .asFunction(); + + static final _set_pi = + jniLookup>( + "set_Fields__pi") + .asFunction(); + + /// from: static public double pi + static double get pi => _get_pi().doubleFloat; + + /// from: static public double pi + static set pi(double value) => _set_pi(value).check(); + + static final _get_asterisk = + jniLookup>( + "get_Fields__asterisk") + .asFunction(); + + static final _set_asterisk = + jniLookup>( + "set_Fields__asterisk") + .asFunction(); + + /// from: static public char asterisk + static int get asterisk => _get_asterisk().char; + + /// from: static public char asterisk + static set asterisk(int value) => _set_asterisk(value).check(); + + static final _get_name = + jniLookup>( + "get_Fields__name") + .asFunction(); + + static final _set_name = jniLookup< + ffi + .NativeFunction)>>( + "set_Fields__name") + .asFunction)>(); + + /// from: static public java.lang.String name + /// The returned object must be released after use, by calling the [release] method. + static jni.JString get name => + const jni.JStringType().fromRef(_get_name().object); + + /// from: static public java.lang.String name + /// The returned object must be released after use, by calling the [release] method. + static set name(jni.JString value) => _set_name(value.reference).check(); + + static final _get_i = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>>("get_Fields__i") + .asFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>(); + + static final _set_i = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, ffi.Pointer)>>("set_Fields__i") + .asFunction< + jni.JniResult Function(jni.JObjectPtr, ffi.Pointer)>(); + + /// from: public java.lang.Integer i + /// The returned object must be released after use, by calling the [release] method. + jni.JInteger get i => + const jni.JIntegerType().fromRef(_get_i(reference).object); + + /// from: public java.lang.Integer i + /// The returned object must be released after use, by calling the [release] method. + set i(jni.JInteger value) => _set_i(reference, value.reference).check(); + + static final _get_trillion = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>>("get_Fields__trillion") + .asFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>(); + + static final _set_trillion = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, ffi.Int64)>>("set_Fields__trillion") + .asFunction(); + + /// from: public long trillion + int get trillion => _get_trillion(reference).long; + + /// from: public long trillion + set trillion(int value) => _set_trillion(reference, value).check(); + + static final _get_isAchillesDead = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>>("get_Fields__isAchillesDead") + .asFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>(); + + static final _set_isAchillesDead = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, ffi.Uint8)>>("set_Fields__isAchillesDead") + .asFunction(); + + /// from: public boolean isAchillesDead + bool get isAchillesDead => _get_isAchillesDead(reference).boolean; + + /// from: public boolean isAchillesDead + set isAchillesDead(bool value) => + _set_isAchillesDead(reference, value ? 1 : 0).check(); + + static final _get_bestFighterInGreece = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>>("get_Fields__bestFighterInGreece") + .asFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>(); + + static final _set_bestFighterInGreece = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(jni.JObjectPtr, + ffi.Pointer)>>("set_Fields__bestFighterInGreece") + .asFunction< + jni.JniResult Function(jni.JObjectPtr, ffi.Pointer)>(); + + /// from: public java.lang.String bestFighterInGreece + /// The returned object must be released after use, by calling the [release] method. + jni.JString get bestFighterInGreece => const jni.JStringType() + .fromRef(_get_bestFighterInGreece(reference).object); + + /// from: public java.lang.String bestFighterInGreece + /// The returned object must be released after use, by calling the [release] method. + set bestFighterInGreece(jni.JString value) => + _set_bestFighterInGreece(reference, value.reference).check(); + + static final _get_random = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>>("get_Fields__random") + .asFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>(); + + static final _set_random = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, ffi.Pointer)>>("set_Fields__random") + .asFunction< + jni.JniResult Function(jni.JObjectPtr, ffi.Pointer)>(); + + /// from: public java.util.Random random + /// The returned object must be released after use, by calling the [release] method. + jni.JObject get random => + const jni.JObjectType().fromRef(_get_random(reference).object); + + /// from: public java.util.Random random + /// The returned object must be released after use, by calling the [release] method. + set random(jni.JObject value) => + _set_random(reference, value.reference).check(); + + static final _get_euroSymbol = + jniLookup>( + "get_Fields__euroSymbol") + .asFunction(); + + static final _set_euroSymbol = + jniLookup>( + "set_Fields__euroSymbol") + .asFunction(); + + /// from: static public char euroSymbol + static int get euroSymbol => _get_euroSymbol().char; + + /// from: static public char euroSymbol + static set euroSymbol(int value) => _set_euroSymbol(value).check(); + + static final _new0 = + jniLookup>("Fields__new0") + .asFunction(); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory Fields() { + return Fields.fromRef(_new0().object); + } +} + +final class $FieldsType extends jni.JObjType { + const $FieldsType(); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/simple_package/Fields;"; + + @override + Fields fromRef(jni.JObjectPtr ref) => Fields.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($FieldsType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($FieldsType) && other is $FieldsType; + } +} + +/// from: com.github.dart_lang.jnigen.simple_package.Fields$Nested +class Fields_Nested extends jni.JObject { + @override + late final jni.JObjType $type = type; + + Fields_Nested.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $Fields_NestedType(); + static final _get_hundred = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>>("get_Fields_Nested__hundred") + .asFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>(); + + static final _set_hundred = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, ffi.Int64)>>("set_Fields_Nested__hundred") + .asFunction(); + + /// from: public long hundred + int get hundred => _get_hundred(reference).long; + + /// from: public long hundred + set hundred(int value) => _set_hundred(reference, value).check(); + + static final _get_BEST_GOD = + jniLookup>( + "get_Fields_Nested__BEST_GOD") + .asFunction(); + + static final _set_BEST_GOD = jniLookup< + ffi + .NativeFunction)>>( + "set_Fields_Nested__BEST_GOD") + .asFunction)>(); + + /// from: static public java.lang.String BEST_GOD + /// The returned object must be released after use, by calling the [release] method. + static jni.JString get BEST_GOD => + const jni.JStringType().fromRef(_get_BEST_GOD().object); + + /// from: static public java.lang.String BEST_GOD + /// The returned object must be released after use, by calling the [release] method. + static set BEST_GOD(jni.JString value) => + _set_BEST_GOD(value.reference).check(); + + static final _new0 = jniLookup>( + "Fields_Nested__new0") + .asFunction(); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory Fields_Nested() { + return Fields_Nested.fromRef(_new0().object); + } +} + +final class $Fields_NestedType extends jni.JObjType { + const $Fields_NestedType(); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/simple_package/Fields$Nested;"; + + @override + Fields_Nested fromRef(jni.JObjectPtr ref) => Fields_Nested.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($Fields_NestedType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($Fields_NestedType) && + other is $Fields_NestedType; + } +} + +/// from: com.github.dart_lang.jnigen.pkg2.C2 +class C2 extends jni.JObject { + @override + late final jni.JObjType $type = type; + + C2.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $C2Type(); + static final _get_CONSTANT = + jniLookup>( + "get_C2__CONSTANT") + .asFunction(); + + static final _set_CONSTANT = + jniLookup>( + "set_C2__CONSTANT") + .asFunction(); + + /// from: static public int CONSTANT + static int get CONSTANT => _get_CONSTANT().integer; + + /// from: static public int CONSTANT + static set CONSTANT(int value) => _set_CONSTANT(value).check(); + + static final _new0 = + jniLookup>("C2__new0") + .asFunction(); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory C2() { + return C2.fromRef(_new0().object); + } +} + +final class $C2Type extends jni.JObjType { + const $C2Type(); + + @override + String get signature => r"Lcom/github/dart_lang/jnigen/pkg2/C2;"; + + @override + C2 fromRef(jni.JObjectPtr ref) => C2.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($C2Type).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($C2Type) && other is $C2Type; + } +} + +/// from: com.github.dart_lang.jnigen.pkg2.Example +class Example1 extends jni.JObject { + @override + late final jni.JObjType $type = type; + + Example1.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $Example1Type(); + static final _new0 = + jniLookup>("Example1__new0") + .asFunction(); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory Example1() { + return Example1.fromRef(_new0().object); + } + + static final _whichExample = jniLookup< + ffi + .NativeFunction)>>( + "Example1__whichExample") + .asFunction)>(); + + /// from: public int whichExample() + int whichExample() { + return _whichExample(reference).integer; + } +} + +final class $Example1Type extends jni.JObjType { + const $Example1Type(); + + @override + String get signature => r"Lcom/github/dart_lang/jnigen/pkg2/Example;"; + + @override + Example1 fromRef(jni.JObjectPtr ref) => Example1.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($Example1Type).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($Example1Type) && other is $Example1Type; + } +} + +/// from: com.github.dart_lang.jnigen.generics.GenericTypeParams +class GenericTypeParams<$S extends jni.JObject, $K extends jni.JObject> + extends jni.JObject { + @override + late final jni.JObjType> $type = type(S, K); + + final jni.JObjType<$S> S; + final jni.JObjType<$K> K; + + GenericTypeParams.fromRef( + this.S, + this.K, + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static $GenericTypeParamsType<$S, $K> + type<$S extends jni.JObject, $K extends jni.JObject>( + jni.JObjType<$S> S, + jni.JObjType<$K> K, + ) { + return $GenericTypeParamsType( + S, + K, + ); + } + + static final _new0 = jniLookup>( + "GenericTypeParams__new0") + .asFunction(); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory GenericTypeParams({ + required jni.JObjType<$S> S, + required jni.JObjType<$K> K, + }) { + return GenericTypeParams.fromRef(S, K, _new0().object); + } +} + +final class $GenericTypeParamsType<$S extends jni.JObject, + $K extends jni.JObject> extends jni.JObjType> { + final jni.JObjType<$S> S; + final jni.JObjType<$K> K; + + const $GenericTypeParamsType( + this.S, + this.K, + ); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/generics/GenericTypeParams;"; + + @override + GenericTypeParams<$S, $K> fromRef(jni.JObjectPtr ref) => + GenericTypeParams.fromRef(S, K, ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => Object.hash($GenericTypeParamsType, S, K); + + @override + bool operator ==(Object other) { + return other.runtimeType == ($GenericTypeParamsType<$S, $K>) && + other is $GenericTypeParamsType<$S, $K> && + S == other.S && + K == other.K; + } +} + +/// from: com.github.dart_lang.jnigen.generics.GrandParent +class GrandParent<$T extends jni.JObject> extends jni.JObject { + @override + late final jni.JObjType> $type = type(T); + + final jni.JObjType<$T> T; + + GrandParent.fromRef( + this.T, + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static $GrandParentType<$T> type<$T extends jni.JObject>( + jni.JObjType<$T> T, + ) { + return $GrandParentType( + T, + ); + } + + static final _get_value = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>>("get_GrandParent__value") + .asFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>(); + + static final _set_value = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(jni.JObjectPtr, + ffi.Pointer)>>("set_GrandParent__value") + .asFunction< + jni.JniResult Function(jni.JObjectPtr, ffi.Pointer)>(); + + /// from: public T value + /// The returned object must be released after use, by calling the [release] method. + $T get value => T.fromRef(_get_value(reference).object); + + /// from: public T value + /// The returned object must be released after use, by calling the [release] method. + set value($T value) => _set_value(reference, value.reference).check(); + + static final _new0 = jniLookup< + ffi + .NativeFunction)>>( + "GrandParent__new0") + .asFunction)>(); + + /// from: public void (T value) + /// The returned object must be released after use, by calling the [release] method. + factory GrandParent( + $T value, { + jni.JObjType<$T>? T, + }) { + T ??= jni.lowestCommonSuperType([ + value.$type, + ]) as jni.JObjType<$T>; + return GrandParent.fromRef(T, _new0(value.reference).object); + } + + static final _stringParent = jniLookup< + ffi + .NativeFunction)>>( + "GrandParent__stringParent") + .asFunction)>(); + + /// from: public com.github.dart_lang.jnigen.generics.GrandParent.Parent stringParent() + /// The returned object must be released after use, by calling the [release] method. + GrandParent_Parent stringParent() { + return const $GrandParent_ParentType(jni.JObjectType(), jni.JStringType()) + .fromRef(_stringParent(reference).object); + } + + static final _varParent = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("GrandParent__varParent") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public com.github.dart_lang.jnigen.generics.GrandParent.Parent varParent(S nestedValue) + /// The returned object must be released after use, by calling the [release] method. + GrandParent_Parent varParent<$S extends jni.JObject>( + $S nestedValue, { + jni.JObjType<$S>? S, + }) { + S ??= jni.lowestCommonSuperType([ + nestedValue.$type, + ]) as jni.JObjType<$S>; + return $GrandParent_ParentType(const jni.JObjectType(), S) + .fromRef(_varParent(reference, nestedValue.reference).object); + } + + static final _stringStaticParent = + jniLookup>( + "GrandParent__stringStaticParent") + .asFunction(); + + /// from: static public com.github.dart_lang.jnigen.generics.GrandParent.StaticParent stringStaticParent() + /// The returned object must be released after use, by calling the [release] method. + static GrandParent_StaticParent stringStaticParent() { + return const $GrandParent_StaticParentType(jni.JStringType()) + .fromRef(_stringStaticParent().object); + } + + static final _varStaticParent = jniLookup< + ffi + .NativeFunction)>>( + "GrandParent__varStaticParent") + .asFunction)>(); + + /// from: static public com.github.dart_lang.jnigen.generics.GrandParent.StaticParent varStaticParent(S value) + /// The returned object must be released after use, by calling the [release] method. + static GrandParent_StaticParent<$S> varStaticParent<$S extends jni.JObject>( + $S value, { + jni.JObjType<$S>? S, + }) { + S ??= jni.lowestCommonSuperType([ + value.$type, + ]) as jni.JObjType<$S>; + return $GrandParent_StaticParentType(S) + .fromRef(_varStaticParent(value.reference).object); + } + + static final _staticParentWithSameType = jniLookup< + ffi + .NativeFunction)>>( + "GrandParent__staticParentWithSameType") + .asFunction)>(); + + /// from: public com.github.dart_lang.jnigen.generics.GrandParent.StaticParent staticParentWithSameType() + /// The returned object must be released after use, by calling the [release] method. + GrandParent_StaticParent<$T> staticParentWithSameType() { + return $GrandParent_StaticParentType(T) + .fromRef(_staticParentWithSameType(reference).object); + } +} + +final class $GrandParentType<$T extends jni.JObject> + extends jni.JObjType> { + final jni.JObjType<$T> T; + + const $GrandParentType( + this.T, + ); + + @override + String get signature => r"Lcom/github/dart_lang/jnigen/generics/GrandParent;"; + + @override + GrandParent<$T> fromRef(jni.JObjectPtr ref) => GrandParent.fromRef(T, ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => Object.hash($GrandParentType, T); + + @override + bool operator ==(Object other) { + return other.runtimeType == ($GrandParentType<$T>) && + other is $GrandParentType<$T> && + T == other.T; + } +} + +/// from: com.github.dart_lang.jnigen.generics.GrandParent$Parent +class GrandParent_Parent<$T extends jni.JObject, $S extends jni.JObject> + extends jni.JObject { + @override + late final jni.JObjType> $type = type(T, S); + + final jni.JObjType<$T> T; + final jni.JObjType<$S> S; + + GrandParent_Parent.fromRef( + this.T, + this.S, + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static $GrandParent_ParentType<$T, $S> + type<$T extends jni.JObject, $S extends jni.JObject>( + jni.JObjType<$T> T, + jni.JObjType<$S> S, + ) { + return $GrandParent_ParentType( + T, + S, + ); + } + + static final _get_parentValue = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>>("get_GrandParent_Parent__parentValue") + .asFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>(); + + static final _set_parentValue = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, ffi.Pointer)>>( + "set_GrandParent_Parent__parentValue") + .asFunction< + jni.JniResult Function(jni.JObjectPtr, ffi.Pointer)>(); + + /// from: public T parentValue + /// The returned object must be released after use, by calling the [release] method. + $T get parentValue => T.fromRef(_get_parentValue(reference).object); + + /// from: public T parentValue + /// The returned object must be released after use, by calling the [release] method. + set parentValue($T value) => + _set_parentValue(reference, value.reference).check(); + + static final _get_value = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>>("get_GrandParent_Parent__value") + .asFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>(); + + static final _set_value = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(jni.JObjectPtr, + ffi.Pointer)>>("set_GrandParent_Parent__value") + .asFunction< + jni.JniResult Function(jni.JObjectPtr, ffi.Pointer)>(); + + /// from: public S value + /// The returned object must be released after use, by calling the [release] method. + $S get value => S.fromRef(_get_value(reference).object); + + /// from: public S value + /// The returned object must be released after use, by calling the [release] method. + set value($S value) => _set_value(reference, value.reference).check(); + + static final _new0 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("GrandParent_Parent__new0") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void (com.github.dart_lang.jnigen.generics.GrandParent $parent, S newValue) + /// The returned object must be released after use, by calling the [release] method. + factory GrandParent_Parent( + GrandParent<$T> $parent, + $S newValue, { + jni.JObjType<$T>? T, + jni.JObjType<$S>? S, + }) { + T ??= jni.lowestCommonSuperType([ + ($parent.$type as $GrandParentType).T, + ]) as jni.JObjType<$T>; + S ??= jni.lowestCommonSuperType([ + newValue.$type, + ]) as jni.JObjType<$S>; + return GrandParent_Parent.fromRef( + T, S, _new0($parent.reference, newValue.reference).object); + } +} + +final class $GrandParent_ParentType<$T extends jni.JObject, + $S extends jni.JObject> extends jni.JObjType> { + final jni.JObjType<$T> T; + final jni.JObjType<$S> S; + + const $GrandParent_ParentType( + this.T, + this.S, + ); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/generics/GrandParent$Parent;"; + + @override + GrandParent_Parent<$T, $S> fromRef(jni.JObjectPtr ref) => + GrandParent_Parent.fromRef(T, S, ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => Object.hash($GrandParent_ParentType, T, S); + + @override + bool operator ==(Object other) { + return other.runtimeType == ($GrandParent_ParentType<$T, $S>) && + other is $GrandParent_ParentType<$T, $S> && + T == other.T && + S == other.S; + } +} + +/// from: com.github.dart_lang.jnigen.generics.GrandParent$Parent$Child +class GrandParent_Parent_Child<$T extends jni.JObject, $S extends jni.JObject, + $U extends jni.JObject> extends jni.JObject { + @override + late final jni.JObjType> $type = + type(T, S, U); + + final jni.JObjType<$T> T; + final jni.JObjType<$S> S; + final jni.JObjType<$U> U; + + GrandParent_Parent_Child.fromRef( + this.T, + this.S, + this.U, + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static $GrandParent_Parent_ChildType<$T, $S, $U> type<$T extends jni.JObject, + $S extends jni.JObject, $U extends jni.JObject>( + jni.JObjType<$T> T, + jni.JObjType<$S> S, + jni.JObjType<$U> U, + ) { + return $GrandParent_Parent_ChildType( + T, + S, + U, + ); + } + + static final _get_grandParentValue = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>>("get_GrandParent_Parent_Child__grandParentValue") + .asFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>(); + + static final _set_grandParentValue = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, ffi.Pointer)>>( + "set_GrandParent_Parent_Child__grandParentValue") + .asFunction< + jni.JniResult Function(jni.JObjectPtr, ffi.Pointer)>(); + + /// from: public T grandParentValue + /// The returned object must be released after use, by calling the [release] method. + $T get grandParentValue => T.fromRef(_get_grandParentValue(reference).object); + + /// from: public T grandParentValue + /// The returned object must be released after use, by calling the [release] method. + set grandParentValue($T value) => + _set_grandParentValue(reference, value.reference).check(); + + static final _get_parentValue = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>>("get_GrandParent_Parent_Child__parentValue") + .asFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>(); + + static final _set_parentValue = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, ffi.Pointer)>>( + "set_GrandParent_Parent_Child__parentValue") + .asFunction< + jni.JniResult Function(jni.JObjectPtr, ffi.Pointer)>(); + + /// from: public S parentValue + /// The returned object must be released after use, by calling the [release] method. + $S get parentValue => S.fromRef(_get_parentValue(reference).object); + + /// from: public S parentValue + /// The returned object must be released after use, by calling the [release] method. + set parentValue($S value) => + _set_parentValue(reference, value.reference).check(); + + static final _get_value = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>>("get_GrandParent_Parent_Child__value") + .asFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>(); + + static final _set_value = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, ffi.Pointer)>>( + "set_GrandParent_Parent_Child__value") + .asFunction< + jni.JniResult Function(jni.JObjectPtr, ffi.Pointer)>(); + + /// from: public U value + /// The returned object must be released after use, by calling the [release] method. + $U get value => U.fromRef(_get_value(reference).object); + + /// from: public U value + /// The returned object must be released after use, by calling the [release] method. + set value($U value) => _set_value(reference, value.reference).check(); + + static final _new0 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("GrandParent_Parent_Child__new0") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void (com.github.dart_lang.jnigen.generics.GrandParent$Parent $parent, U newValue) + /// The returned object must be released after use, by calling the [release] method. + factory GrandParent_Parent_Child( + GrandParent_Parent<$T, $S> $parent, + $U newValue, { + jni.JObjType<$T>? T, + jni.JObjType<$S>? S, + jni.JObjType<$U>? U, + }) { + T ??= jni.lowestCommonSuperType([ + ($parent.$type as $GrandParent_ParentType).T, + ]) as jni.JObjType<$T>; + S ??= jni.lowestCommonSuperType([ + ($parent.$type as $GrandParent_ParentType).S, + ]) as jni.JObjType<$S>; + U ??= jni.lowestCommonSuperType([ + newValue.$type, + ]) as jni.JObjType<$U>; + return GrandParent_Parent_Child.fromRef( + T, S, U, _new0($parent.reference, newValue.reference).object); + } +} + +final class $GrandParent_Parent_ChildType<$T extends jni.JObject, + $S extends jni.JObject, $U extends jni.JObject> + extends jni.JObjType> { + final jni.JObjType<$T> T; + final jni.JObjType<$S> S; + final jni.JObjType<$U> U; + + const $GrandParent_Parent_ChildType( + this.T, + this.S, + this.U, + ); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/generics/GrandParent$Parent$Child;"; + + @override + GrandParent_Parent_Child<$T, $S, $U> fromRef(jni.JObjectPtr ref) => + GrandParent_Parent_Child.fromRef(T, S, U, ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => Object.hash($GrandParent_Parent_ChildType, T, S, U); + + @override + bool operator ==(Object other) { + return other.runtimeType == ($GrandParent_Parent_ChildType<$T, $S, $U>) && + other is $GrandParent_Parent_ChildType<$T, $S, $U> && + T == other.T && + S == other.S && + U == other.U; + } +} + +/// from: com.github.dart_lang.jnigen.generics.GrandParent$StaticParent +class GrandParent_StaticParent<$S extends jni.JObject> extends jni.JObject { + @override + late final jni.JObjType> $type = type(S); + + final jni.JObjType<$S> S; + + GrandParent_StaticParent.fromRef( + this.S, + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static $GrandParent_StaticParentType<$S> type<$S extends jni.JObject>( + jni.JObjType<$S> S, + ) { + return $GrandParent_StaticParentType( + S, + ); + } + + static final _get_value = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>>("get_GrandParent_StaticParent__value") + .asFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>(); + + static final _set_value = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, ffi.Pointer)>>( + "set_GrandParent_StaticParent__value") + .asFunction< + jni.JniResult Function(jni.JObjectPtr, ffi.Pointer)>(); + + /// from: public S value + /// The returned object must be released after use, by calling the [release] method. + $S get value => S.fromRef(_get_value(reference).object); + + /// from: public S value + /// The returned object must be released after use, by calling the [release] method. + set value($S value) => _set_value(reference, value.reference).check(); + + static final _new0 = jniLookup< + ffi + .NativeFunction)>>( + "GrandParent_StaticParent__new0") + .asFunction)>(); + + /// from: public void (S value) + /// The returned object must be released after use, by calling the [release] method. + factory GrandParent_StaticParent( + $S value, { + jni.JObjType<$S>? S, + }) { + S ??= jni.lowestCommonSuperType([ + value.$type, + ]) as jni.JObjType<$S>; + return GrandParent_StaticParent.fromRef(S, _new0(value.reference).object); + } +} + +final class $GrandParent_StaticParentType<$S extends jni.JObject> + extends jni.JObjType> { + final jni.JObjType<$S> S; + + const $GrandParent_StaticParentType( + this.S, + ); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/generics/GrandParent$StaticParent;"; + + @override + GrandParent_StaticParent<$S> fromRef(jni.JObjectPtr ref) => + GrandParent_StaticParent.fromRef(S, ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => Object.hash($GrandParent_StaticParentType, S); + + @override + bool operator ==(Object other) { + return other.runtimeType == ($GrandParent_StaticParentType<$S>) && + other is $GrandParent_StaticParentType<$S> && + S == other.S; + } +} + +/// from: com.github.dart_lang.jnigen.generics.GrandParent$StaticParent$Child +class GrandParent_StaticParent_Child<$S extends jni.JObject, + $U extends jni.JObject> extends jni.JObject { + @override + late final jni.JObjType> $type = + type(S, U); + + final jni.JObjType<$S> S; + final jni.JObjType<$U> U; + + GrandParent_StaticParent_Child.fromRef( + this.S, + this.U, + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static $GrandParent_StaticParent_ChildType<$S, $U> + type<$S extends jni.JObject, $U extends jni.JObject>( + jni.JObjType<$S> S, + jni.JObjType<$U> U, + ) { + return $GrandParent_StaticParent_ChildType( + S, + U, + ); + } + + static final _get_parentValue = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>>("get_GrandParent_StaticParent_Child__parentValue") + .asFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>(); + + static final _set_parentValue = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, ffi.Pointer)>>( + "set_GrandParent_StaticParent_Child__parentValue") + .asFunction< + jni.JniResult Function(jni.JObjectPtr, ffi.Pointer)>(); + + /// from: public S parentValue + /// The returned object must be released after use, by calling the [release] method. + $S get parentValue => S.fromRef(_get_parentValue(reference).object); + + /// from: public S parentValue + /// The returned object must be released after use, by calling the [release] method. + set parentValue($S value) => + _set_parentValue(reference, value.reference).check(); + + static final _get_value = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>>("get_GrandParent_StaticParent_Child__value") + .asFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>(); + + static final _set_value = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, ffi.Pointer)>>( + "set_GrandParent_StaticParent_Child__value") + .asFunction< + jni.JniResult Function(jni.JObjectPtr, ffi.Pointer)>(); + + /// from: public U value + /// The returned object must be released after use, by calling the [release] method. + $U get value => U.fromRef(_get_value(reference).object); + + /// from: public U value + /// The returned object must be released after use, by calling the [release] method. + set value($U value) => _set_value(reference, value.reference).check(); + + static final _new0 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer, ffi.Pointer)>>( + "GrandParent_StaticParent_Child__new0") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); + + /// from: public void (com.github.dart_lang.jnigen.generics.GrandParent$StaticParent $parent, S parentValue, U value) + /// The returned object must be released after use, by calling the [release] method. + factory GrandParent_StaticParent_Child( + GrandParent_StaticParent<$S> $parent, + $S parentValue, + $U value, { + jni.JObjType<$S>? S, + jni.JObjType<$U>? U, + }) { + S ??= jni.lowestCommonSuperType([ + parentValue.$type, + ($parent.$type as $GrandParent_StaticParentType).S, + ]) as jni.JObjType<$S>; + U ??= jni.lowestCommonSuperType([ + value.$type, + ]) as jni.JObjType<$U>; + return GrandParent_StaticParent_Child.fromRef( + S, + U, + _new0($parent.reference, parentValue.reference, value.reference) + .object); + } +} + +final class $GrandParent_StaticParent_ChildType<$S extends jni.JObject, + $U extends jni.JObject> + extends jni.JObjType> { + final jni.JObjType<$S> S; + final jni.JObjType<$U> U; + + const $GrandParent_StaticParent_ChildType( + this.S, + this.U, + ); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/generics/GrandParent$StaticParent$Child;"; + + @override + GrandParent_StaticParent_Child<$S, $U> fromRef(jni.JObjectPtr ref) => + GrandParent_StaticParent_Child.fromRef(S, U, ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => Object.hash($GrandParent_StaticParent_ChildType, S, U); + + @override + bool operator ==(Object other) { + return other.runtimeType == ($GrandParent_StaticParent_ChildType<$S, $U>) && + other is $GrandParent_StaticParent_ChildType<$S, $U> && + S == other.S && + U == other.U; + } +} + +/// from: com.github.dart_lang.jnigen.generics.MyMap +class MyMap<$K extends jni.JObject, $V extends jni.JObject> + extends jni.JObject { + @override + late final jni.JObjType> $type = type(K, V); + + final jni.JObjType<$K> K; + final jni.JObjType<$V> V; + + MyMap.fromRef( + this.K, + this.V, + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static $MyMapType<$K, $V> + type<$K extends jni.JObject, $V extends jni.JObject>( + jni.JObjType<$K> K, + jni.JObjType<$V> V, + ) { + return $MyMapType( + K, + V, + ); + } + + static final _new0 = + jniLookup>("MyMap__new0") + .asFunction(); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory MyMap({ + required jni.JObjType<$K> K, + required jni.JObjType<$V> V, + }) { + return MyMap.fromRef(K, V, _new0().object); + } + + static final _get0 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>>("MyMap__get0") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public V get(K key) + /// The returned object must be released after use, by calling the [release] method. + $V get0( + $K key, + ) { + return V.fromRef(_get0(reference, key.reference).object); + } + + static final _put = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer, ffi.Pointer)>>("MyMap__put") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); + + /// from: public V put(K key, V value) + /// The returned object must be released after use, by calling the [release] method. + $V put( + $K key, + $V value, + ) { + return V.fromRef(_put(reference, key.reference, value.reference).object); + } + + static final _entryStack = jniLookup< + ffi + .NativeFunction)>>( + "MyMap__entryStack") + .asFunction)>(); + + /// from: public com.github.dart_lang.jnigen.generics.MyStack.MyEntry> entryStack() + /// The returned object must be released after use, by calling the [release] method. + MyStack> entryStack() { + return const $MyStackType( + $MyMap_MyEntryType(jni.JObjectType(), jni.JObjectType())) + .fromRef(_entryStack(reference).object); + } +} + +final class $MyMapType<$K extends jni.JObject, $V extends jni.JObject> + extends jni.JObjType> { + final jni.JObjType<$K> K; + final jni.JObjType<$V> V; + + const $MyMapType( + this.K, + this.V, + ); + + @override + String get signature => r"Lcom/github/dart_lang/jnigen/generics/MyMap;"; + + @override + MyMap<$K, $V> fromRef(jni.JObjectPtr ref) => MyMap.fromRef(K, V, ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => Object.hash($MyMapType, K, V); + + @override + bool operator ==(Object other) { + return other.runtimeType == ($MyMapType<$K, $V>) && + other is $MyMapType<$K, $V> && + K == other.K && + V == other.V; + } +} + +/// from: com.github.dart_lang.jnigen.generics.MyMap$MyEntry +class MyMap_MyEntry<$K extends jni.JObject, $V extends jni.JObject> + extends jni.JObject { + @override + late final jni.JObjType> $type = type(K, V); + + final jni.JObjType<$K> K; + final jni.JObjType<$V> V; + + MyMap_MyEntry.fromRef( + this.K, + this.V, + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static $MyMap_MyEntryType<$K, $V> + type<$K extends jni.JObject, $V extends jni.JObject>( + jni.JObjType<$K> K, + jni.JObjType<$V> V, + ) { + return $MyMap_MyEntryType( + K, + V, + ); + } + + static final _get_key = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>>("get_MyMap_MyEntry__key") + .asFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>(); + + static final _set_key = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(jni.JObjectPtr, + ffi.Pointer)>>("set_MyMap_MyEntry__key") + .asFunction< + jni.JniResult Function(jni.JObjectPtr, ffi.Pointer)>(); + + /// from: public K key + /// The returned object must be released after use, by calling the [release] method. + $K get key => K.fromRef(_get_key(reference).object); + + /// from: public K key + /// The returned object must be released after use, by calling the [release] method. + set key($K value) => _set_key(reference, value.reference).check(); + + static final _get_value = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>>("get_MyMap_MyEntry__value") + .asFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>(); + + static final _set_value = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(jni.JObjectPtr, + ffi.Pointer)>>("set_MyMap_MyEntry__value") + .asFunction< + jni.JniResult Function(jni.JObjectPtr, ffi.Pointer)>(); + + /// from: public V value + /// The returned object must be released after use, by calling the [release] method. + $V get value => V.fromRef(_get_value(reference).object); + + /// from: public V value + /// The returned object must be released after use, by calling the [release] method. + set value($V value) => _set_value(reference, value.reference).check(); + + static final _new0 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>("MyMap_MyEntry__new0") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); + + /// from: public void (com.github.dart_lang.jnigen.generics.MyMap $parent, K key, V value) + /// The returned object must be released after use, by calling the [release] method. + factory MyMap_MyEntry( + MyMap<$K, $V> $parent, + $K key, + $V value, { + jni.JObjType<$K>? K, + jni.JObjType<$V>? V, + }) { + K ??= jni.lowestCommonSuperType([ + key.$type, + ($parent.$type as $MyMapType).K, + ]) as jni.JObjType<$K>; + V ??= jni.lowestCommonSuperType([ + value.$type, + ($parent.$type as $MyMapType).V, + ]) as jni.JObjType<$V>; + return MyMap_MyEntry.fromRef( + K, V, _new0($parent.reference, key.reference, value.reference).object); + } +} + +final class $MyMap_MyEntryType<$K extends jni.JObject, $V extends jni.JObject> + extends jni.JObjType> { + final jni.JObjType<$K> K; + final jni.JObjType<$V> V; + + const $MyMap_MyEntryType( + this.K, + this.V, + ); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/generics/MyMap$MyEntry;"; + + @override + MyMap_MyEntry<$K, $V> fromRef(jni.JObjectPtr ref) => + MyMap_MyEntry.fromRef(K, V, ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => Object.hash($MyMap_MyEntryType, K, V); + + @override + bool operator ==(Object other) { + return other.runtimeType == ($MyMap_MyEntryType<$K, $V>) && + other is $MyMap_MyEntryType<$K, $V> && + K == other.K && + V == other.V; + } +} + +/// from: com.github.dart_lang.jnigen.generics.MyStack +class MyStack<$T extends jni.JObject> extends jni.JObject { + @override + late final jni.JObjType> $type = type(T); + + final jni.JObjType<$T> T; + + MyStack.fromRef( + this.T, + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static $MyStackType<$T> type<$T extends jni.JObject>( + jni.JObjType<$T> T, + ) { + return $MyStackType( + T, + ); + } + + static final _new0 = + jniLookup>("MyStack__new0") + .asFunction(); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory MyStack({ + required jni.JObjType<$T> T, + }) { + return MyStack.fromRef(T, _new0().object); + } + + static final _fromArray = jniLookup< + ffi + .NativeFunction)>>( + "MyStack__fromArray") + .asFunction)>(); + + /// from: static public com.github.dart_lang.jnigen.generics.MyStack fromArray(T[] arr) + /// The returned object must be released after use, by calling the [release] method. + static MyStack<$T> fromArray<$T extends jni.JObject>( + jni.JArray<$T> arr, { + jni.JObjType<$T>? T, + }) { + T ??= jni.lowestCommonSuperType([ + ((arr.$type as jni.JArrayType).elementType as jni.JObjType), + ]) as jni.JObjType<$T>; + return $MyStackType(T).fromRef(_fromArray(arr.reference).object); + } + + static final _fromArrayOfArrayOfGrandParents = jniLookup< + ffi + .NativeFunction)>>( + "MyStack__fromArrayOfArrayOfGrandParents") + .asFunction)>(); + + /// from: static public com.github.dart_lang.jnigen.generics.MyStack fromArrayOfArrayOfGrandParents(com.github.dart_lang.jnigen.generics.GrandParent[][] arr) + /// The returned object must be released after use, by calling the [release] method. + static MyStack<$S> fromArrayOfArrayOfGrandParents<$S extends jni.JObject>( + jni.JArray>> arr, { + jni.JObjType<$S>? S, + }) { + S ??= jni.lowestCommonSuperType([ + (((((arr.$type as jni.JArrayType).elementType as jni.JObjType) + as jni.JArrayType) + .elementType as jni.JObjType) as $GrandParentType) + .T, + ]) as jni.JObjType<$S>; + return $MyStackType(S) + .fromRef(_fromArrayOfArrayOfGrandParents(arr.reference).object); + } + + static final _of = + jniLookup>("MyStack__of") + .asFunction(); + + /// from: static public com.github.dart_lang.jnigen.generics.MyStack of() + /// The returned object must be released after use, by calling the [release] method. + static MyStack<$T> of<$T extends jni.JObject>({ + required jni.JObjType<$T> T, + }) { + return $MyStackType(T).fromRef(_of().object); + } + + static final _of1 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer)>>("MyStack__of1") + .asFunction)>(); + + /// from: static public com.github.dart_lang.jnigen.generics.MyStack of(T obj) + /// The returned object must be released after use, by calling the [release] method. + static MyStack<$T> of1<$T extends jni.JObject>( + $T obj, { + jni.JObjType<$T>? T, + }) { + T ??= jni.lowestCommonSuperType([ + obj.$type, + ]) as jni.JObjType<$T>; + return $MyStackType(T).fromRef(_of1(obj.reference).object); + } + + static final _of2 = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("MyStack__of2") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: static public com.github.dart_lang.jnigen.generics.MyStack of(T obj, T obj2) + /// The returned object must be released after use, by calling the [release] method. + static MyStack<$T> of2<$T extends jni.JObject>( + $T obj, + $T obj2, { + jni.JObjType<$T>? T, + }) { + T ??= jni.lowestCommonSuperType([ + obj2.$type, + obj.$type, + ]) as jni.JObjType<$T>; + return $MyStackType(T).fromRef(_of2(obj.reference, obj2.reference).object); + } + + static final _push = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("MyStack__push") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public void push(T item) + void push( + $T item, + ) { + return _push(reference, item.reference).check(); + } + + static final _pop = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer)>>("MyStack__pop") + .asFunction)>(); + + /// from: public T pop() + /// The returned object must be released after use, by calling the [release] method. + $T pop() { + return T.fromRef(_pop(reference).object); + } + + static final _size = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer)>>("MyStack__size") + .asFunction)>(); + + /// from: public int size() + int size() { + return _size(reference).integer; + } +} + +final class $MyStackType<$T extends jni.JObject> + extends jni.JObjType> { + final jni.JObjType<$T> T; + + const $MyStackType( + this.T, + ); + + @override + String get signature => r"Lcom/github/dart_lang/jnigen/generics/MyStack;"; + + @override + MyStack<$T> fromRef(jni.JObjectPtr ref) => MyStack.fromRef(T, ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => Object.hash($MyStackType, T); + + @override + bool operator ==(Object other) { + return other.runtimeType == ($MyStackType<$T>) && + other is $MyStackType<$T> && + T == other.T; + } +} + +/// from: com.github.dart_lang.jnigen.generics.StringKeyedMap +class StringKeyedMap<$V extends jni.JObject> extends MyMap { + @override + late final jni.JObjType> $type = type(V); + + final jni.JObjType<$V> V; + + StringKeyedMap.fromRef( + this.V, + jni.JObjectPtr ref, + ) : super.fromRef(const jni.JStringType(), V, ref); + + /// The type which includes information such as the signature of this class. + static $StringKeyedMapType<$V> type<$V extends jni.JObject>( + jni.JObjType<$V> V, + ) { + return $StringKeyedMapType( + V, + ); + } + + static final _new0 = jniLookup>( + "StringKeyedMap__new0") + .asFunction(); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory StringKeyedMap({ + required jni.JObjType<$V> V, + }) { + return StringKeyedMap.fromRef(V, _new0().object); + } +} + +final class $StringKeyedMapType<$V extends jni.JObject> + extends jni.JObjType> { + final jni.JObjType<$V> V; + + const $StringKeyedMapType( + this.V, + ); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/generics/StringKeyedMap;"; + + @override + StringKeyedMap<$V> fromRef(jni.JObjectPtr ref) => + StringKeyedMap.fromRef(V, ref); + + @override + jni.JObjType get superType => $MyMapType(const jni.JStringType(), V); + + @override + final superCount = 2; + + @override + int get hashCode => Object.hash($StringKeyedMapType, V); + + @override + bool operator ==(Object other) { + return other.runtimeType == ($StringKeyedMapType<$V>) && + other is $StringKeyedMapType<$V> && + V == other.V; + } +} + +/// from: com.github.dart_lang.jnigen.generics.StringMap +class StringMap extends StringKeyedMap { + @override + late final jni.JObjType $type = type; + + StringMap.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(const jni.JStringType(), ref); + + /// The type which includes information such as the signature of this class. + static const type = $StringMapType(); + static final _new0 = + jniLookup>("StringMap__new0") + .asFunction(); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory StringMap() { + return StringMap.fromRef(_new0().object); + } +} + +final class $StringMapType extends jni.JObjType { + const $StringMapType(); + + @override + String get signature => r"Lcom/github/dart_lang/jnigen/generics/StringMap;"; + + @override + StringMap fromRef(jni.JObjectPtr ref) => StringMap.fromRef(ref); + + @override + jni.JObjType get superType => const $StringKeyedMapType(jni.JStringType()); + + @override + final superCount = 3; + + @override + int get hashCode => ($StringMapType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($StringMapType) && other is $StringMapType; + } +} + +/// from: com.github.dart_lang.jnigen.generics.StringStack +class StringStack extends MyStack { + @override + late final jni.JObjType $type = type; + + StringStack.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(const jni.JStringType(), ref); + + /// The type which includes information such as the signature of this class. + static const type = $StringStackType(); + static final _new0 = jniLookup>( + "StringStack__new0") + .asFunction(); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory StringStack() { + return StringStack.fromRef(_new0().object); + } +} + +final class $StringStackType extends jni.JObjType { + const $StringStackType(); + + @override + String get signature => r"Lcom/github/dart_lang/jnigen/generics/StringStack;"; + + @override + StringStack fromRef(jni.JObjectPtr ref) => StringStack.fromRef(ref); + + @override + jni.JObjType get superType => const $MyStackType(jni.JStringType()); + + @override + final superCount = 2; + + @override + int get hashCode => ($StringStackType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($StringStackType) && other is $StringStackType; + } +} + +/// from: com.github.dart_lang.jnigen.generics.StringValuedMap +class StringValuedMap<$K extends jni.JObject> extends MyMap<$K, jni.JString> { + @override + late final jni.JObjType> $type = type(K); + + final jni.JObjType<$K> K; + + StringValuedMap.fromRef( + this.K, + jni.JObjectPtr ref, + ) : super.fromRef(K, const jni.JStringType(), ref); + + /// The type which includes information such as the signature of this class. + static $StringValuedMapType<$K> type<$K extends jni.JObject>( + jni.JObjType<$K> K, + ) { + return $StringValuedMapType( + K, + ); + } + + static final _new0 = jniLookup>( + "StringValuedMap__new0") + .asFunction(); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory StringValuedMap({ + required jni.JObjType<$K> K, + }) { + return StringValuedMap.fromRef(K, _new0().object); + } +} + +final class $StringValuedMapType<$K extends jni.JObject> + extends jni.JObjType> { + final jni.JObjType<$K> K; + + const $StringValuedMapType( + this.K, + ); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/generics/StringValuedMap;"; + + @override + StringValuedMap<$K> fromRef(jni.JObjectPtr ref) => + StringValuedMap.fromRef(K, ref); + + @override + jni.JObjType get superType => $MyMapType(K, const jni.JStringType()); + + @override + final superCount = 2; + + @override + int get hashCode => Object.hash($StringValuedMapType, K); + + @override + bool operator ==(Object other) { + return other.runtimeType == ($StringValuedMapType<$K>) && + other is $StringValuedMapType<$K> && + K == other.K; + } +} + +/// from: com.github.dart_lang.jnigen.interfaces.MyInterface +class MyInterface<$T extends jni.JObject> extends jni.JObject { + @override + late final jni.JObjType> $type = type(T); + + final jni.JObjType<$T> T; + + MyInterface.fromRef( + this.T, + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static $MyInterfaceType<$T> type<$T extends jni.JObject>( + jni.JObjType<$T> T, + ) { + return $MyInterfaceType( + T, + ); + } + + static final _voidCallback = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("MyInterface__voidCallback") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public abstract void voidCallback(java.lang.String s) + void voidCallback( + jni.JString s, + ) { + return _voidCallback(reference, s.reference).check(); + } + + static final _stringCallback = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("MyInterface__stringCallback") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public abstract java.lang.String stringCallback(java.lang.String s) + /// The returned object must be released after use, by calling the [release] method. + jni.JString stringCallback( + jni.JString s, + ) { + return const jni.JStringType() + .fromRef(_stringCallback(reference, s.reference).object); + } + + static final _varCallback = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer, + ffi.Pointer)>>("MyInterface__varCallback") + .asFunction< + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); + + /// from: public abstract T varCallback(T t) + /// The returned object must be released after use, by calling the [release] method. + $T varCallback( + $T t, + ) { + return T.fromRef(_varCallback(reference, t.reference).object); + } + + static final _manyPrimitives = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Int32, + ffi.Uint8, + ffi.Uint16, + ffi.Double)>>("MyInterface__manyPrimitives") + .asFunction< + jni.JniResult Function( + ffi.Pointer, int, int, int, double)>(); + + /// from: public abstract long manyPrimitives(int a, boolean b, char c, double d) + int manyPrimitives( + int a, + bool b, + int c, + double d, + ) { + return _manyPrimitives(reference, a, b ? 1 : 0, c, d).long; + } + + /// Maps a specific port to the implemented interface. + static final Map _$impls = {}; + ReceivePort? _$p; + + static jni.JObjectPtr _$invoke( + int port, + jni.JObjectPtr descriptor, + jni.JObjectPtr args, + ) { + return _$invokeMethod( + port, + $MethodInvocation.fromAddresses( + 0, + descriptor.address, + args.address, + ), + ); + } + + static final ffi.Pointer< + ffi.NativeFunction< + jni.JObjectPtr Function( + ffi.Uint64, jni.JObjectPtr, jni.JObjectPtr)>> + _$invokePointer = ffi.Pointer.fromFunction(_$invoke); + + static ffi.Pointer _$invokeMethod( + int $p, + $MethodInvocation $i, + ) { + try { + final $d = $i.methodDescriptor.toDartString(releaseOriginal: true); + final $a = $i.args; + if ($d == r"voidCallback(Ljava/lang/String;)V") { + _$impls[$p]!.voidCallback( + $a[0].castTo(const jni.JStringType(), releaseOriginal: true), + ); + return jni.nullptr; + } + if ($d == r"stringCallback(Ljava/lang/String;)Ljava/lang/String;") { + final $r = _$impls[$p]!.stringCallback( + $a[0].castTo(const jni.JStringType(), releaseOriginal: true), + ); + return ($r as jni.JObject).castTo(const jni.JObjectType()).toPointer(); + } + if ($d == r"varCallback(Ljava/lang/Object;)Ljava/lang/Object;") { + final $r = _$impls[$p]!.varCallback( + $a[0].castTo(_$impls[$p]!.T, releaseOriginal: true), + ); + return ($r as jni.JObject).castTo(const jni.JObjectType()).toPointer(); + } + if ($d == r"manyPrimitives(IZCD)J") { + final $r = _$impls[$p]!.manyPrimitives( + $a[0] + .castTo(const jni.JIntegerType(), releaseOriginal: true) + .intValue(releaseOriginal: true), + $a[1] + .castTo(const jni.JBooleanType(), releaseOriginal: true) + .booleanValue(releaseOriginal: true), + $a[2] + .castTo(const jni.JCharacterType(), releaseOriginal: true) + .charValue(releaseOriginal: true), + $a[3] + .castTo(const jni.JDoubleType(), releaseOriginal: true) + .doubleValue(releaseOriginal: true), + ); + return jni.JLong($r).toPointer(); + } + } catch (e) { + return ProtectedJniExtensions.newDartException(e.toString()); + } + return jni.nullptr; + } + + factory MyInterface.implement( + $MyInterfaceImpl<$T> $impl, + ) { + final $p = ReceivePort(); + final $x = MyInterface.fromRef( + $impl.T, + ProtectedJniExtensions.newPortProxy( + r"com.github.dart_lang.jnigen.interfaces.MyInterface", + $p, + _$invokePointer, + ), + ).._$p = $p; + final $a = $p.sendPort.nativePort; + _$impls[$a] = $impl; + $p.listen(($m) { + if ($m == null) { + _$impls.remove($p.sendPort.nativePort); + $p.close(); + return; + } + final $i = $MethodInvocation.fromMessage($m as List); + final $r = _$invokeMethod($p.sendPort.nativePort, $i); + ProtectedJniExtensions.returnResult($i.result, $r); + }); + return $x; + } + static Map get $impls => _$impls; +} + +abstract interface class $MyInterfaceImpl<$T extends jni.JObject> { + factory $MyInterfaceImpl({ + required jni.JObjType<$T> T, + required void Function(jni.JString s) voidCallback, + required jni.JString Function(jni.JString s) stringCallback, + required $T Function($T t) varCallback, + required int Function(int a, bool b, int c, double d) manyPrimitives, + }) = _$MyInterfaceImpl; + + jni.JObjType<$T> get T; + + void voidCallback(jni.JString s); + jni.JString stringCallback(jni.JString s); + $T varCallback($T t); + int manyPrimitives(int a, bool b, int c, double d); +} + +class _$MyInterfaceImpl<$T extends jni.JObject> + implements $MyInterfaceImpl<$T> { + _$MyInterfaceImpl({ + required this.T, + required void Function(jni.JString s) voidCallback, + required jni.JString Function(jni.JString s) stringCallback, + required $T Function($T t) varCallback, + required int Function(int a, bool b, int c, double d) manyPrimitives, + }) : _voidCallback = voidCallback, + _stringCallback = stringCallback, + _varCallback = varCallback, + _manyPrimitives = manyPrimitives; + + @override + final jni.JObjType<$T> T; + + final void Function(jni.JString s) _voidCallback; + final jni.JString Function(jni.JString s) _stringCallback; + final $T Function($T t) _varCallback; + final int Function(int a, bool b, int c, double d) _manyPrimitives; + + void voidCallback(jni.JString s) { + return _voidCallback(s); + } + + jni.JString stringCallback(jni.JString s) { + return _stringCallback(s); + } + + $T varCallback($T t) { + return _varCallback(t); + } + + int manyPrimitives(int a, bool b, int c, double d) { + return _manyPrimitives(a, b, c, d); + } +} + +final class $MyInterfaceType<$T extends jni.JObject> + extends jni.JObjType> { + final jni.JObjType<$T> T; + + const $MyInterfaceType( + this.T, + ); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/interfaces/MyInterface;"; + + @override + MyInterface<$T> fromRef(jni.JObjectPtr ref) => MyInterface.fromRef(T, ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => Object.hash($MyInterfaceType, T); + + @override + bool operator ==(Object other) { + return other.runtimeType == ($MyInterfaceType<$T>) && + other is $MyInterfaceType<$T> && + T == other.T; + } +} + +/// from: com.github.dart_lang.jnigen.interfaces.MyInterfaceConsumer +class MyInterfaceConsumer extends jni.JObject { + @override + late final jni.JObjType $type = type; + + MyInterfaceConsumer.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $MyInterfaceConsumerType(); + static final _new0 = jniLookup>( + "MyInterfaceConsumer__new0") + .asFunction(); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory MyInterfaceConsumer() { + return MyInterfaceConsumer.fromRef(_new0().object); + } + + static final _consumeOnAnotherThread = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Int32, + ffi.Uint8, + ffi.Uint16, + ffi.Double, + ffi.Pointer)>>( + "MyInterfaceConsumer__consumeOnAnotherThread") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + int, int, int, double, ffi.Pointer)>(); + + /// from: static public void consumeOnAnotherThread(com.github.dart_lang.jnigen.interfaces.MyInterface myInterface, java.lang.String s, int a, boolean b, char c, double d, T t) + static void consumeOnAnotherThread<$T extends jni.JObject>( + MyInterface<$T> myInterface, + jni.JString s, + int a, + bool b, + int c, + double d, + $T t, { + jni.JObjType<$T>? T, + }) { + T ??= jni.lowestCommonSuperType([ + t.$type, + (myInterface.$type as $MyInterfaceType).T, + ]) as jni.JObjType<$T>; + return _consumeOnAnotherThread( + myInterface.reference, s.reference, a, b ? 1 : 0, c, d, t.reference) + .check(); + } + + static final _consumeOnSameThread = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, + ffi.Int32, + ffi.Uint8, + ffi.Uint16, + ffi.Double, + ffi.Pointer)>>( + "MyInterfaceConsumer__consumeOnSameThread") + .asFunction< + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + int, int, int, double, ffi.Pointer)>(); + + /// from: static public void consumeOnSameThread(com.github.dart_lang.jnigen.interfaces.MyInterface myInterface, java.lang.String s, int a, boolean b, char c, double d, T t) + static void consumeOnSameThread<$T extends jni.JObject>( + MyInterface<$T> myInterface, + jni.JString s, + int a, + bool b, + int c, + double d, + $T t, { + jni.JObjType<$T>? T, + }) { + T ??= jni.lowestCommonSuperType([ + t.$type, + (myInterface.$type as $MyInterfaceType).T, + ]) as jni.JObjType<$T>; + return _consumeOnSameThread( + myInterface.reference, s.reference, a, b ? 1 : 0, c, d, t.reference) + .check(); + } +} + +final class $MyInterfaceConsumerType extends jni.JObjType { + const $MyInterfaceConsumerType(); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/interfaces/MyInterfaceConsumer;"; + + @override + MyInterfaceConsumer fromRef(jni.JObjectPtr ref) => + MyInterfaceConsumer.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($MyInterfaceConsumerType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($MyInterfaceConsumerType) && + other is $MyInterfaceConsumerType; + } +} + +/// from: com.github.dart_lang.jnigen.interfaces.MyRunnable +class MyRunnable extends jni.JObject { + @override + late final jni.JObjType $type = type; + + MyRunnable.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $MyRunnableType(); + static final _run = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(ffi.Pointer)>>("MyRunnable__run") + .asFunction)>(); + + /// from: public abstract void run() + void run() { + return _run(reference).check(); + } + + /// Maps a specific port to the implemented interface. + static final Map _$impls = {}; + ReceivePort? _$p; + + static jni.JObjectPtr _$invoke( + int port, + jni.JObjectPtr descriptor, + jni.JObjectPtr args, + ) { + return _$invokeMethod( + port, + $MethodInvocation.fromAddresses( + 0, + descriptor.address, + args.address, + ), + ); + } + + static final ffi.Pointer< + ffi.NativeFunction< + jni.JObjectPtr Function( + ffi.Uint64, jni.JObjectPtr, jni.JObjectPtr)>> + _$invokePointer = ffi.Pointer.fromFunction(_$invoke); + + static ffi.Pointer _$invokeMethod( + int $p, + $MethodInvocation $i, + ) { + try { + final $d = $i.methodDescriptor.toDartString(releaseOriginal: true); + final $a = $i.args; + if ($d == r"run()V") { + _$impls[$p]!.run(); + return jni.nullptr; + } + } catch (e) { + return ProtectedJniExtensions.newDartException(e.toString()); + } + return jni.nullptr; + } + + factory MyRunnable.implement( + $MyRunnableImpl $impl, + ) { + final $p = ReceivePort(); + final $x = MyRunnable.fromRef( + ProtectedJniExtensions.newPortProxy( + r"com.github.dart_lang.jnigen.interfaces.MyRunnable", + $p, + _$invokePointer, + ), + ).._$p = $p; + final $a = $p.sendPort.nativePort; + _$impls[$a] = $impl; + $p.listen(($m) { + if ($m == null) { + _$impls.remove($p.sendPort.nativePort); + $p.close(); + return; + } + final $i = $MethodInvocation.fromMessage($m as List); + final $r = _$invokeMethod($p.sendPort.nativePort, $i); + ProtectedJniExtensions.returnResult($i.result, $r); + }); + return $x; + } +} + +abstract interface class $MyRunnableImpl { + factory $MyRunnableImpl({ + required void Function() run, + }) = _$MyRunnableImpl; + + void run(); +} + +class _$MyRunnableImpl implements $MyRunnableImpl { + _$MyRunnableImpl({ + required void Function() run, + }) : _run = run; + + final void Function() _run; + + void run() { + return _run(); + } +} + +final class $MyRunnableType extends jni.JObjType { + const $MyRunnableType(); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/interfaces/MyRunnable;"; + + @override + MyRunnable fromRef(jni.JObjectPtr ref) => MyRunnable.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($MyRunnableType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($MyRunnableType) && other is $MyRunnableType; + } +} + +/// from: com.github.dart_lang.jnigen.interfaces.MyRunnableRunner +class MyRunnableRunner extends jni.JObject { + @override + late final jni.JObjType $type = type; + + MyRunnableRunner.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $MyRunnableRunnerType(); + static final _get_error = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>>("get_MyRunnableRunner__error") + .asFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>(); + + static final _set_error = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(jni.JObjectPtr, + ffi.Pointer)>>("set_MyRunnableRunner__error") + .asFunction< + jni.JniResult Function(jni.JObjectPtr, ffi.Pointer)>(); + + /// from: public java.lang.Throwable error + /// The returned object must be released after use, by calling the [release] method. + jni.JObject get error => + const jni.JObjectType().fromRef(_get_error(reference).object); + + /// from: public java.lang.Throwable error + /// The returned object must be released after use, by calling the [release] method. + set error(jni.JObject value) => + _set_error(reference, value.reference).check(); + + static final _new0 = jniLookup< + ffi + .NativeFunction)>>( + "MyRunnableRunner__new0") + .asFunction)>(); + + /// from: public void (com.github.dart_lang.jnigen.interfaces.MyRunnable runnable) + /// The returned object must be released after use, by calling the [release] method. + factory MyRunnableRunner( + MyRunnable runnable, + ) { + return MyRunnableRunner.fromRef(_new0(runnable.reference).object); + } + + static final _runOnSameThread = jniLookup< + ffi + .NativeFunction)>>( + "MyRunnableRunner__runOnSameThread") + .asFunction)>(); + + /// from: public void runOnSameThread() + void runOnSameThread() { + return _runOnSameThread(reference).check(); + } + + static final _runOnAnotherThread = jniLookup< + ffi + .NativeFunction)>>( + "MyRunnableRunner__runOnAnotherThread") + .asFunction)>(); + + /// from: public void runOnAnotherThread() + void runOnAnotherThread() { + return _runOnAnotherThread(reference).check(); + } +} + +final class $MyRunnableRunnerType extends jni.JObjType { + const $MyRunnableRunnerType(); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/interfaces/MyRunnableRunner;"; + + @override + MyRunnableRunner fromRef(jni.JObjectPtr ref) => MyRunnableRunner.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($MyRunnableRunnerType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($MyRunnableRunnerType) && + other is $MyRunnableRunnerType; + } +} + +/// from: com.github.dart_lang.jnigen.annotations.JsonSerializable$Case +class JsonSerializable_Case extends jni.JObject { + @override + late final jni.JObjType $type = type; + + JsonSerializable_Case.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $JsonSerializable_CaseType(); + static final _values = + jniLookup>( + "JsonSerializable_Case__values") + .asFunction(); + + /// from: static public com.github.dart_lang.jnigen.annotations.JsonSerializable.Case[] values() + /// The returned object must be released after use, by calling the [release] method. + static jni.JArray values() { + return const jni.JArrayType($JsonSerializable_CaseType()) + .fromRef(_values().object); + } + + static final _valueOf = jniLookup< + ffi + .NativeFunction)>>( + "JsonSerializable_Case__valueOf") + .asFunction)>(); + + /// from: static public com.github.dart_lang.jnigen.annotations.JsonSerializable.Case valueOf(java.lang.String name) + /// The returned object must be released after use, by calling the [release] method. + static JsonSerializable_Case valueOf( + jni.JString name, + ) { + return const $JsonSerializable_CaseType() + .fromRef(_valueOf(name.reference).object); + } +} + +final class $JsonSerializable_CaseType + extends jni.JObjType { + const $JsonSerializable_CaseType(); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/annotations/JsonSerializable$Case;"; + + @override + JsonSerializable_Case fromRef(jni.JObjectPtr ref) => + JsonSerializable_Case.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($JsonSerializable_CaseType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($JsonSerializable_CaseType) && + other is $JsonSerializable_CaseType; + } +} + +/// from: com.github.dart_lang.jnigen.annotations.MyDataClass +class MyDataClass extends jni.JObject { + @override + late final jni.JObjType $type = type; + + MyDataClass.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $MyDataClassType(); + static final _new0 = jniLookup>( + "MyDataClass__new0") + .asFunction(); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory MyDataClass() { + return MyDataClass.fromRef(_new0().object); + } +} + +final class $MyDataClassType extends jni.JObjType { + const $MyDataClassType(); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/annotations/MyDataClass;"; + + @override + MyDataClass fromRef(jni.JObjectPtr ref) => MyDataClass.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($MyDataClassType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($MyDataClassType) && other is $MyDataClassType; + } +} diff --git a/pkgs/jnigen/test/simple_package_test/dart_only/dart_bindings/simple_package.dart b/pkgs/jnigen/test/simple_package_test/dart_only/dart_bindings/simple_package.dart new file mode 100644 index 000000000..ba022690f --- /dev/null +++ b/pkgs/jnigen/test/simple_package_test/dart_only/dart_bindings/simple_package.dart @@ -0,0 +1,3805 @@ +// 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. + +// Autogenerated by jnigen. DO NOT EDIT! + +// ignore_for_file: annotate_overrides +// ignore_for_file: camel_case_extensions +// ignore_for_file: camel_case_types +// ignore_for_file: constant_identifier_names +// ignore_for_file: file_names +// ignore_for_file: lines_longer_than_80_chars +// ignore_for_file: no_leading_underscores_for_local_identifiers +// ignore_for_file: non_constant_identifier_names +// ignore_for_file: overridden_fields +// ignore_for_file: unnecessary_cast +// ignore_for_file: unused_element +// ignore_for_file: unused_field +// ignore_for_file: unused_import +// ignore_for_file: unused_local_variable +// ignore_for_file: unused_shown_name + +import "dart:isolate" show ReceivePort; +import "dart:ffi" as ffi; +import "package:jni/internal_helpers_for_jnigen.dart"; +import "package:jni/jni.dart" as jni; + +/// from: com.github.dart_lang.jnigen.simple_package.Color +class Color extends jni.JObject { + @override + late final jni.JObjType $type = type; + + Color.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = + jni.Jni.findJClass(r"com/github/dart_lang/jnigen/simple_package/Color"); + + /// The type which includes information such as the signature of this class. + static const type = $ColorType(); + static final _id_values = jni.Jni.accessors.getStaticMethodIDOf( + _class.reference, + r"values", + r"()[Lcom/github/dart_lang/jnigen/simple_package/Color;"); + + /// from: static public com.github.dart_lang.jnigen.simple_package.Color[] values() + /// The returned object must be released after use, by calling the [release] method. + static jni.JArray values() { + return const jni.JArrayType($ColorType()).fromRef(jni.Jni.accessors + .callStaticMethodWithArgs(_class.reference, _id_values, + jni.JniCallType.objectType, []).object); + } + + static final _id_valueOf = jni.Jni.accessors.getStaticMethodIDOf( + _class.reference, + r"valueOf", + r"(Ljava/lang/String;)Lcom/github/dart_lang/jnigen/simple_package/Color;"); + + /// from: static public com.github.dart_lang.jnigen.simple_package.Color valueOf(java.lang.String name) + /// The returned object must be released after use, by calling the [release] method. + static Color valueOf( + jni.JString name, + ) { + return const $ColorType().fromRef(jni.Jni.accessors + .callStaticMethodWithArgs(_class.reference, _id_valueOf, + jni.JniCallType.objectType, [name.reference]).object); + } +} + +final class $ColorType extends jni.JObjType { + const $ColorType(); + + @override + String get signature => r"Lcom/github/dart_lang/jnigen/simple_package/Color;"; + + @override + Color fromRef(jni.JObjectPtr ref) => Color.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($ColorType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($ColorType) && other is $ColorType; + } +} + +/// from: com.github.dart_lang.jnigen.simple_package.Example +class Example extends jni.JObject { + @override + late final jni.JObjType $type = type; + + Example.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = + jni.Jni.findJClass(r"com/github/dart_lang/jnigen/simple_package/Example"); + + /// The type which includes information such as the signature of this class. + static const type = $ExampleType(); + + /// from: static public final int ON + static const ON = 1; + + /// from: static public final int OFF + static const OFF = 0; + + /// from: static public final double PI + static const PI = 3.14159; + + /// from: static public final char SEMICOLON + static const SEMICOLON = 59; + + /// from: static public final java.lang.String SEMICOLON_STRING + static const SEMICOLON_STRING = r""";"""; + + static final _id_unusedRandom = jni.Jni.accessors.getStaticFieldIDOf( + _class.reference, + r"unusedRandom", + r"Ljava/util/Random;", + ); + + /// from: static public final java.util.Random unusedRandom + /// The returned object must be released after use, by calling the [release] method. + static jni.JObject get unusedRandom => + const jni.JObjectType().fromRef(jni.Jni.accessors + .getStaticField( + _class.reference, _id_unusedRandom, jni.JniCallType.objectType) + .object); + + static final _id_protectedField = jni.Jni.accessors.getFieldIDOf( + _class.reference, + r"protectedField", + r"Ljava/util/Random;", + ); + + /// from: protected java.util.Random protectedField + /// The returned object must be released after use, by calling the [release] method. + jni.JObject get protectedField => + const jni.JObjectType().fromRef(jni.Jni.accessors + .getField(reference, _id_protectedField, jni.JniCallType.objectType) + .object); + + /// from: protected java.util.Random protectedField + /// The returned object must be released after use, by calling the [release] method. + set protectedField(jni.JObject value) => jni.Jni.env + .SetObjectField(reference, _id_protectedField, value.reference); + + static final _id_getAmount = jni.Jni.accessors + .getStaticMethodIDOf(_class.reference, r"getAmount", r"()I"); + + /// from: static public int getAmount() + static int getAmount() { + return jni.Jni.accessors.callStaticMethodWithArgs( + _class.reference, _id_getAmount, jni.JniCallType.intType, []).integer; + } + + static final _id_getPi = + jni.Jni.accessors.getStaticMethodIDOf(_class.reference, r"getPi", r"()D"); + + /// from: static public double getPi() + static double getPi() { + return jni.Jni.accessors.callStaticMethodWithArgs(_class.reference, + _id_getPi, jni.JniCallType.doubleType, []).doubleFloat; + } + + static final _id_getAsterisk = jni.Jni.accessors + .getStaticMethodIDOf(_class.reference, r"getAsterisk", r"()C"); + + /// from: static public char getAsterisk() + static int getAsterisk() { + return jni.Jni.accessors.callStaticMethodWithArgs( + _class.reference, _id_getAsterisk, jni.JniCallType.charType, []).char; + } + + static final _id_getName = jni.Jni.accessors.getStaticMethodIDOf( + _class.reference, r"getName", r"()Ljava/lang/String;"); + + /// from: static public java.lang.String getName() + /// The returned object must be released after use, by calling the [release] method. + static jni.JString getName() { + return const jni.JStringType().fromRef(jni.Jni.accessors + .callStaticMethodWithArgs(_class.reference, _id_getName, + jni.JniCallType.objectType, []).object); + } + + static final _id_getNestedInstance = jni.Jni.accessors.getStaticMethodIDOf( + _class.reference, + r"getNestedInstance", + r"()Lcom/github/dart_lang/jnigen/simple_package/Example$Nested;"); + + /// from: static public com.github.dart_lang.jnigen.simple_package.Example.Nested getNestedInstance() + /// The returned object must be released after use, by calling the [release] method. + static Example_Nested getNestedInstance() { + return const $Example_NestedType().fromRef(jni.Jni.accessors + .callStaticMethodWithArgs(_class.reference, _id_getNestedInstance, + jni.JniCallType.objectType, []).object); + } + + static final _id_setAmount = jni.Jni.accessors + .getStaticMethodIDOf(_class.reference, r"setAmount", r"(I)V"); + + /// from: static public void setAmount(int newAmount) + static void setAmount( + int newAmount, + ) { + return jni.Jni.accessors.callStaticMethodWithArgs( + _class.reference, + _id_setAmount, + jni.JniCallType.voidType, + [jni.JValueInt(newAmount)]).check(); + } + + static final _id_setName = jni.Jni.accessors.getStaticMethodIDOf( + _class.reference, r"setName", r"(Ljava/lang/String;)V"); + + /// from: static public void setName(java.lang.String newName) + static void setName( + jni.JString newName, + ) { + return jni.Jni.accessors.callStaticMethodWithArgs(_class.reference, + _id_setName, jni.JniCallType.voidType, [newName.reference]).check(); + } + + static final _id_setNestedInstance = jni.Jni.accessors.getStaticMethodIDOf( + _class.reference, + r"setNestedInstance", + r"(Lcom/github/dart_lang/jnigen/simple_package/Example$Nested;)V"); + + /// from: static public void setNestedInstance(com.github.dart_lang.jnigen.simple_package.Example.Nested newNested) + static void setNestedInstance( + Example_Nested newNested, + ) { + return jni.Jni.accessors.callStaticMethodWithArgs( + _class.reference, + _id_setNestedInstance, + jni.JniCallType.voidType, + [newNested.reference]).check(); + } + + static final _id_max4 = jni.Jni.accessors + .getStaticMethodIDOf(_class.reference, r"max4", r"(IIII)I"); + + /// from: static public int max4(int a, int b, int c, int d) + static int max4( + int a, + int b, + int c, + int d, + ) { + return jni.Jni.accessors.callStaticMethodWithArgs( + _class.reference, _id_max4, jni.JniCallType.intType, [ + jni.JValueInt(a), + jni.JValueInt(b), + jni.JValueInt(c), + jni.JValueInt(d) + ]).integer; + } + + static final _id_max8 = jni.Jni.accessors + .getStaticMethodIDOf(_class.reference, r"max8", r"(IIIIIIII)I"); + + /// from: static public int max8(int a, int b, int c, int d, int e, int f, int g, int h) + static int max8( + int a, + int b, + int c, + int d, + int e, + int f, + int g, + int h, + ) { + return jni.Jni.accessors.callStaticMethodWithArgs( + _class.reference, _id_max8, jni.JniCallType.intType, [ + jni.JValueInt(a), + jni.JValueInt(b), + jni.JValueInt(c), + jni.JValueInt(d), + jni.JValueInt(e), + jni.JValueInt(f), + jni.JValueInt(g), + jni.JValueInt(h) + ]).integer; + } + + static final _id_getNumber = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"getNumber", r"()I"); + + /// from: public int getNumber() + int getNumber() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_getNumber, jni.JniCallType.intType, []).integer; + } + + static final _id_setNumber = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"setNumber", r"(I)V"); + + /// from: public void setNumber(int number) + void setNumber( + int number, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_setNumber, + jni.JniCallType.voidType, [jni.JValueInt(number)]).check(); + } + + static final _id_getIsUp = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"getIsUp", r"()Z"); + + /// from: public boolean getIsUp() + bool getIsUp() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_getIsUp, jni.JniCallType.booleanType, []).boolean; + } + + static final _id_setUp = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"setUp", r"(Z)V"); + + /// from: public void setUp(boolean isUp) + void setUp( + bool isUp, + ) { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_setUp, jni.JniCallType.voidType, [isUp ? 1 : 0]).check(); + } + + static final _id_getCodename = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"getCodename", r"()Ljava/lang/String;"); + + /// from: public java.lang.String getCodename() + /// The returned object must be released after use, by calling the [release] method. + jni.JString getCodename() { + return const jni.JStringType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, _id_getCodename, jni.JniCallType.objectType, []).object); + } + + static final _id_setCodename = jni.Jni.accessors.getMethodIDOf( + _class.reference, r"setCodename", r"(Ljava/lang/String;)V"); + + /// from: public void setCodename(java.lang.String codename) + void setCodename( + jni.JString codename, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_setCodename, + jni.JniCallType.voidType, [codename.reference]).check(); + } + + static final _id_getRandom = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"getRandom", r"()Ljava/util/Random;"); + + /// from: public java.util.Random getRandom() + /// The returned object must be released after use, by calling the [release] method. + jni.JObject getRandom() { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, _id_getRandom, jni.JniCallType.objectType, []).object); + } + + static final _id_setRandom = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"setRandom", r"(Ljava/util/Random;)V"); + + /// from: public void setRandom(java.util.Random random) + void setRandom( + jni.JObject random, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_setRandom, + jni.JniCallType.voidType, [random.reference]).check(); + } + + static final _id_getRandomLong = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"getRandomLong", r"()J"); + + /// from: public long getRandomLong() + int getRandomLong() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_getRandomLong, jni.JniCallType.longType, []).long; + } + + static final _id_add4Longs = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"add4Longs", r"(JJJJ)J"); + + /// from: public long add4Longs(long a, long b, long c, long d) + int add4Longs( + int a, + int b, + int c, + int d, + ) { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_add4Longs, jni.JniCallType.longType, [a, b, c, d]).long; + } + + static final _id_add8Longs = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"add8Longs", r"(JJJJJJJJ)J"); + + /// from: public long add8Longs(long a, long b, long c, long d, long e, long f, long g, long h) + int add8Longs( + int a, + int b, + int c, + int d, + int e, + int f, + int g, + int h, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_add8Longs, + jni.JniCallType.longType, [a, b, c, d, e, f, g, h]).long; + } + + static final _id_getRandomNumericString = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"getRandomNumericString", + r"(Ljava/util/Random;)Ljava/lang/String;"); + + /// from: public java.lang.String getRandomNumericString(java.util.Random random) + /// The returned object must be released after use, by calling the [release] method. + jni.JString getRandomNumericString( + jni.JObject random, + ) { + return const jni.JStringType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_getRandomNumericString, + jni.JniCallType.objectType, + [random.reference]).object); + } + + static final _id_protectedMethod = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"protectedMethod", + r"(Ljava/lang/String;Ljava/lang/String;)V"); + + /// from: protected void protectedMethod(java.lang.String a, java.lang.String b) + void protectedMethod( + jni.JString a, + jni.JString b, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_protectedMethod, + jni.JniCallType.voidType, [a.reference, b.reference]).check(); + } + + static final _id_finalMethod = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"finalMethod", r"()V"); + + /// from: public final void finalMethod() + void finalMethod() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_finalMethod, jni.JniCallType.voidType, []).check(); + } + + static final _id_getList = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"getList", r"()Ljava/util/List;"); + + /// from: public java.util.List getList() + /// The returned object must be released after use, by calling the [release] method. + jni.JList getList() { + return const jni.JListType(jni.JStringType()).fromRef(jni.Jni.accessors + .callMethodWithArgs( + reference, _id_getList, jni.JniCallType.objectType, []).object); + } + + static final _id_joinStrings = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"joinStrings", + r"(Ljava/util/List;Ljava/lang/String;)Ljava/lang/String;"); + + /// from: public java.lang.String joinStrings(java.util.List values, java.lang.String delim) + /// The returned object must be released after use, by calling the [release] method. + /// + /// Joins the strings in the list using the given delimiter. + jni.JString joinStrings( + jni.JList values, + jni.JString delim, + ) { + return const jni.JStringType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_joinStrings, + jni.JniCallType.objectType, + [values.reference, delim.reference]).object); + } + + static final _id_methodWithSeveralParams = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"methodWithSeveralParams", + r"(CLjava/lang/String;[ILjava/lang/CharSequence;Ljava/util/List;Ljava/util/Map;)V"); + + /// from: public void methodWithSeveralParams(char ch, java.lang.String s, int[] a, T t, java.util.List lt, java.util.Map wm) + void methodWithSeveralParams<$T extends jni.JObject>( + int ch, + jni.JString s, + jni.JArray a, + $T t, + jni.JList<$T> lt, + jni.JMap wm, { + jni.JObjType<$T>? T, + }) { + T ??= jni.lowestCommonSuperType([ + (lt.$type as jni.JListType).E, + t.$type, + ]) as jni.JObjType<$T>; + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_methodWithSeveralParams, jni.JniCallType.voidType, [ + jni.JValueChar(ch), + s.reference, + a.reference, + t.reference, + lt.reference, + wm.reference + ]).check(); + } + + static final _id_new0 = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"", r"()V"); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory Example() { + return Example.fromRef(jni.Jni.accessors + .newObjectWithArgs(_class.reference, _id_new0, []).object); + } + + static final _id_new1 = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"", r"(I)V"); + + /// from: public void (int number) + /// The returned object must be released after use, by calling the [release] method. + factory Example.new1( + int number, + ) { + return Example.fromRef(jni.Jni.accessors.newObjectWithArgs( + _class.reference, _id_new1, [jni.JValueInt(number)]).object); + } + + static final _id_new2 = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"", r"(IZ)V"); + + /// from: public void (int number, boolean isUp) + /// The returned object must be released after use, by calling the [release] method. + factory Example.new2( + int number, + bool isUp, + ) { + return Example.fromRef(jni.Jni.accessors.newObjectWithArgs(_class.reference, + _id_new2, [jni.JValueInt(number), isUp ? 1 : 0]).object); + } + + static final _id_new3 = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"", r"(IZLjava/lang/String;)V"); + + /// from: public void (int number, boolean isUp, java.lang.String codename) + /// The returned object must be released after use, by calling the [release] method. + factory Example.new3( + int number, + bool isUp, + jni.JString codename, + ) { + return Example.fromRef(jni.Jni.accessors.newObjectWithArgs( + _class.reference, + _id_new3, + [jni.JValueInt(number), isUp ? 1 : 0, codename.reference]).object); + } + + static final _id_new4 = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"", r"(IIIIIIII)V"); + + /// from: public void (int a, int b, int c, int d, int e, int f, int g, int h) + /// The returned object must be released after use, by calling the [release] method. + factory Example.new4( + int a, + int b, + int c, + int d, + int e, + int f, + int g, + int h, + ) { + return Example.fromRef( + jni.Jni.accessors.newObjectWithArgs(_class.reference, _id_new4, [ + jni.JValueInt(a), + jni.JValueInt(b), + jni.JValueInt(c), + jni.JValueInt(d), + jni.JValueInt(e), + jni.JValueInt(f), + jni.JValueInt(g), + jni.JValueInt(h) + ]).object); + } + + static final _id_whichExample = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"whichExample", r"()I"); + + /// from: public int whichExample() + int whichExample() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_whichExample, jni.JniCallType.intType, []).integer; + } + + static final _id_addInts = jni.Jni.accessors + .getStaticMethodIDOf(_class.reference, r"addInts", r"(II)I"); + + /// from: static public int addInts(int a, int b) + static int addInts( + int a, + int b, + ) { + return jni.Jni.accessors.callStaticMethodWithArgs( + _class.reference, + _id_addInts, + jni.JniCallType.intType, + [jni.JValueInt(a), jni.JValueInt(b)]).integer; + } + + static final _id_getArr = jni.Jni.accessors + .getStaticMethodIDOf(_class.reference, r"getArr", r"()[I"); + + /// from: static public int[] getArr() + /// The returned object must be released after use, by calling the [release] method. + static jni.JArray getArr() { + return const jni.JArrayType(jni.jintType()).fromRef(jni.Jni.accessors + .callStaticMethodWithArgs(_class.reference, _id_getArr, + jni.JniCallType.objectType, []).object); + } + + static final _id_addAll = jni.Jni.accessors + .getStaticMethodIDOf(_class.reference, r"addAll", r"([I)I"); + + /// from: static public int addAll(int[] arr) + static int addAll( + jni.JArray arr, + ) { + return jni.Jni.accessors.callStaticMethodWithArgs(_class.reference, + _id_addAll, jni.JniCallType.intType, [arr.reference]).integer; + } + + static final _id_getSelf = jni.Jni.accessors.getMethodIDOf(_class.reference, + r"getSelf", r"()Lcom/github/dart_lang/jnigen/simple_package/Example;"); + + /// from: public com.github.dart_lang.jnigen.simple_package.Example getSelf() + /// The returned object must be released after use, by calling the [release] method. + Example getSelf() { + return const $ExampleType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, _id_getSelf, jni.JniCallType.objectType, []).object); + } + + static final _id_throwException = jni.Jni.accessors + .getStaticMethodIDOf(_class.reference, r"throwException", r"()V"); + + /// from: static public void throwException() + static void throwException() { + return jni.Jni.accessors.callStaticMethodWithArgs(_class.reference, + _id_throwException, jni.JniCallType.voidType, []).check(); + } + + static final _id_overloaded = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"overloaded", r"()V"); + + /// from: public void overloaded() + void overloaded() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_overloaded, jni.JniCallType.voidType, []).check(); + } + + static final _id_overloaded1 = jni.Jni.accessors.getMethodIDOf( + _class.reference, r"overloaded", r"(ILjava/lang/String;)V"); + + /// from: public void overloaded(int a, java.lang.String b) + void overloaded1( + int a, + jni.JString b, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_overloaded1, + jni.JniCallType.voidType, [jni.JValueInt(a), b.reference]).check(); + } + + static final _id_overloaded2 = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"overloaded", r"(I)V"); + + /// from: public void overloaded(int a) + void overloaded2( + int a, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_overloaded2, + jni.JniCallType.voidType, [jni.JValueInt(a)]).check(); + } + + static final _id_overloaded3 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"overloaded", + r"(Ljava/util/List;Ljava/lang/String;)V"); + + /// from: public void overloaded(java.util.List a, java.lang.String b) + void overloaded3( + jni.JList a, + jni.JString b, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_overloaded3, + jni.JniCallType.voidType, [a.reference, b.reference]).check(); + } + + static final _id_overloaded4 = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"overloaded", r"(Ljava/util/List;)V"); + + /// from: public void overloaded(java.util.List a) + void overloaded4( + jni.JList a, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_overloaded4, + jni.JniCallType.voidType, [a.reference]).check(); + } +} + +final class $ExampleType extends jni.JObjType { + const $ExampleType(); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/simple_package/Example;"; + + @override + Example fromRef(jni.JObjectPtr ref) => Example.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($ExampleType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($ExampleType) && other is $ExampleType; + } +} + +/// from: com.github.dart_lang.jnigen.simple_package.Example$Nested +class Example_Nested extends jni.JObject { + @override + late final jni.JObjType $type = type; + + Example_Nested.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = jni.Jni.findJClass( + r"com/github/dart_lang/jnigen/simple_package/Example$Nested"); + + /// The type which includes information such as the signature of this class. + static const type = $Example_NestedType(); + static final _id_new0 = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"", r"(Z)V"); + + /// from: public void (boolean value) + /// The returned object must be released after use, by calling the [release] method. + factory Example_Nested( + bool value, + ) { + return Example_Nested.fromRef(jni.Jni.accessors + .newObjectWithArgs(_class.reference, _id_new0, [value ? 1 : 0]).object); + } + + static final _id_usesAnonymousInnerClass = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"usesAnonymousInnerClass", r"()V"); + + /// from: public void usesAnonymousInnerClass() + void usesAnonymousInnerClass() { + return jni.Jni.accessors.callMethodWithArgs(reference, + _id_usesAnonymousInnerClass, jni.JniCallType.voidType, []).check(); + } + + static final _id_getValue = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"getValue", r"()Z"); + + /// from: public boolean getValue() + bool getValue() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_getValue, jni.JniCallType.booleanType, []).boolean; + } + + static final _id_setValue = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"setValue", r"(Z)V"); + + /// from: public void setValue(boolean value) + void setValue( + bool value, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_setValue, + jni.JniCallType.voidType, [value ? 1 : 0]).check(); + } +} + +final class $Example_NestedType extends jni.JObjType { + const $Example_NestedType(); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/simple_package/Example$Nested;"; + + @override + Example_Nested fromRef(jni.JObjectPtr ref) => Example_Nested.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($Example_NestedType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($Example_NestedType) && + other is $Example_NestedType; + } +} + +/// from: com.github.dart_lang.jnigen.simple_package.Example$Nested$NestedTwice +class Example_Nested_NestedTwice extends jni.JObject { + @override + late final jni.JObjType $type = type; + + Example_Nested_NestedTwice.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = jni.Jni.findJClass( + r"com/github/dart_lang/jnigen/simple_package/Example$Nested$NestedTwice"); + + /// The type which includes information such as the signature of this class. + static const type = $Example_Nested_NestedTwiceType(); + static final _id_ZERO = jni.Jni.accessors.getStaticFieldIDOf( + _class.reference, + r"ZERO", + r"I", + ); + + /// from: static public int ZERO + static int get ZERO => jni.Jni.accessors + .getStaticField(_class.reference, _id_ZERO, jni.JniCallType.intType) + .integer; + + /// from: static public int ZERO + static set ZERO(int value) => + jni.Jni.env.SetStaticIntField(_class.reference, _id_ZERO, value); + + static final _id_new0 = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"", r"()V"); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory Example_Nested_NestedTwice() { + return Example_Nested_NestedTwice.fromRef(jni.Jni.accessors + .newObjectWithArgs(_class.reference, _id_new0, []).object); + } +} + +final class $Example_Nested_NestedTwiceType + extends jni.JObjType { + const $Example_Nested_NestedTwiceType(); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/simple_package/Example$Nested$NestedTwice;"; + + @override + Example_Nested_NestedTwice fromRef(jni.JObjectPtr ref) => + Example_Nested_NestedTwice.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($Example_Nested_NestedTwiceType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($Example_Nested_NestedTwiceType) && + other is $Example_Nested_NestedTwiceType; + } +} + +/// from: com.github.dart_lang.jnigen.simple_package.Example$NonStaticNested +class Example_NonStaticNested extends jni.JObject { + @override + late final jni.JObjType $type = type; + + Example_NonStaticNested.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = jni.Jni.findJClass( + r"com/github/dart_lang/jnigen/simple_package/Example$NonStaticNested"); + + /// The type which includes information such as the signature of this class. + static const type = $Example_NonStaticNestedType(); + static final _id_ok = jni.Jni.accessors.getFieldIDOf( + _class.reference, + r"ok", + r"Z", + ); + + /// from: public boolean ok + bool get ok => jni.Jni.accessors + .getField(reference, _id_ok, jni.JniCallType.booleanType) + .boolean; + + /// from: public boolean ok + set ok(bool value) => + jni.Jni.env.SetBooleanField(reference, _id_ok, value ? 1 : 0); + + static final _id_new0 = jni.Jni.accessors.getMethodIDOf(_class.reference, + r"", r"(Lcom/github/dart_lang/jnigen/simple_package/Example;)V"); + + /// from: public void (com.github.dart_lang.jnigen.simple_package.Example $parent) + /// The returned object must be released after use, by calling the [release] method. + factory Example_NonStaticNested( + Example $parent, + ) { + return Example_NonStaticNested.fromRef(jni.Jni.accessors.newObjectWithArgs( + _class.reference, _id_new0, [$parent.reference]).object); + } +} + +final class $Example_NonStaticNestedType + extends jni.JObjType { + const $Example_NonStaticNestedType(); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/simple_package/Example$NonStaticNested;"; + + @override + Example_NonStaticNested fromRef(jni.JObjectPtr ref) => + Example_NonStaticNested.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($Example_NonStaticNestedType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($Example_NonStaticNestedType) && + other is $Example_NonStaticNestedType; + } +} + +/// from: com.github.dart_lang.jnigen.simple_package.Exceptions +class Exceptions extends jni.JObject { + @override + late final jni.JObjType $type = type; + + Exceptions.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = jni.Jni.findJClass( + r"com/github/dart_lang/jnigen/simple_package/Exceptions"); + + /// The type which includes information such as the signature of this class. + static const type = $ExceptionsType(); + static final _id_new0 = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"", r"()V"); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory Exceptions() { + return Exceptions.fromRef(jni.Jni.accessors + .newObjectWithArgs(_class.reference, _id_new0, []).object); + } + + static final _id_new1 = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"", r"(F)V"); + + /// from: public void (float x) + /// The returned object must be released after use, by calling the [release] method. + factory Exceptions.new1( + double x, + ) { + return Exceptions.fromRef(jni.Jni.accessors.newObjectWithArgs( + _class.reference, _id_new1, [jni.JValueFloat(x)]).object); + } + + static final _id_new2 = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"", r"(IIIIII)V"); + + /// from: public void (int a, int b, int c, int d, int e, int f) + /// The returned object must be released after use, by calling the [release] method. + factory Exceptions.new2( + int a, + int b, + int c, + int d, + int e, + int f, + ) { + return Exceptions.fromRef( + jni.Jni.accessors.newObjectWithArgs(_class.reference, _id_new2, [ + jni.JValueInt(a), + jni.JValueInt(b), + jni.JValueInt(c), + jni.JValueInt(d), + jni.JValueInt(e), + jni.JValueInt(f) + ]).object); + } + + static final _id_staticObjectMethod = jni.Jni.accessors.getStaticMethodIDOf( + _class.reference, r"staticObjectMethod", r"()Ljava/lang/Object;"); + + /// from: static public java.lang.Object staticObjectMethod() + /// The returned object must be released after use, by calling the [release] method. + static jni.JObject staticObjectMethod() { + return const jni.JObjectType().fromRef(jni.Jni.accessors + .callStaticMethodWithArgs(_class.reference, _id_staticObjectMethod, + jni.JniCallType.objectType, []).object); + } + + static final _id_staticIntMethod = jni.Jni.accessors + .getStaticMethodIDOf(_class.reference, r"staticIntMethod", r"()I"); + + /// from: static public int staticIntMethod() + static int staticIntMethod() { + return jni.Jni.accessors.callStaticMethodWithArgs(_class.reference, + _id_staticIntMethod, jni.JniCallType.intType, []).integer; + } + + static final _id_staticObjectArrayMethod = jni.Jni.accessors + .getStaticMethodIDOf(_class.reference, r"staticObjectArrayMethod", + r"()[Ljava/lang/Object;"); + + /// from: static public java.lang.Object[] staticObjectArrayMethod() + /// The returned object must be released after use, by calling the [release] method. + static jni.JArray staticObjectArrayMethod() { + return const jni.JArrayType(jni.JObjectType()).fromRef(jni.Jni.accessors + .callStaticMethodWithArgs(_class.reference, _id_staticObjectArrayMethod, + jni.JniCallType.objectType, []).object); + } + + static final _id_staticIntArrayMethod = jni.Jni.accessors + .getStaticMethodIDOf(_class.reference, r"staticIntArrayMethod", r"()[I"); + + /// from: static public int[] staticIntArrayMethod() + /// The returned object must be released after use, by calling the [release] method. + static jni.JArray staticIntArrayMethod() { + return const jni.JArrayType(jni.jintType()).fromRef(jni.Jni.accessors + .callStaticMethodWithArgs(_class.reference, _id_staticIntArrayMethod, + jni.JniCallType.objectType, []).object); + } + + static final _id_objectMethod = jni.Jni.accessors.getMethodIDOf( + _class.reference, r"objectMethod", r"()Ljava/lang/Object;"); + + /// from: public java.lang.Object objectMethod() + /// The returned object must be released after use, by calling the [release] method. + jni.JObject objectMethod() { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, _id_objectMethod, jni.JniCallType.objectType, []).object); + } + + static final _id_intMethod = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"intMethod", r"()I"); + + /// from: public int intMethod() + int intMethod() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_intMethod, jni.JniCallType.intType, []).integer; + } + + static final _id_objectArrayMethod = jni.Jni.accessors.getMethodIDOf( + _class.reference, r"objectArrayMethod", r"()[Ljava/lang/Object;"); + + /// from: public java.lang.Object[] objectArrayMethod() + /// The returned object must be released after use, by calling the [release] method. + jni.JArray objectArrayMethod() { + return const jni.JArrayType(jni.JObjectType()).fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_objectArrayMethod, + jni.JniCallType.objectType, []).object); + } + + static final _id_intArrayMethod = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"intArrayMethod", r"()[I"); + + /// from: public int[] intArrayMethod() + /// The returned object must be released after use, by calling the [release] method. + jni.JArray intArrayMethod() { + return const jni.JArrayType(jni.jintType()).fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_intArrayMethod, + jni.JniCallType.objectType, []).object); + } + + static final _id_throwNullPointerException = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"throwNullPointerException", r"()I"); + + /// from: public int throwNullPointerException() + int throwNullPointerException() { + return jni.Jni.accessors.callMethodWithArgs(reference, + _id_throwNullPointerException, jni.JniCallType.intType, []).integer; + } + + static final _id_throwFileNotFoundException = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"throwFileNotFoundException", + r"()Ljava/io/InputStream;"); + + /// from: public java.io.InputStream throwFileNotFoundException() + /// The returned object must be released after use, by calling the [release] method. + jni.JObject throwFileNotFoundException() { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_throwFileNotFoundException, + jni.JniCallType.objectType, []).object); + } + + static final _id_throwClassCastException = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"throwClassCastException", + r"()Ljava/io/FileInputStream;"); + + /// from: public java.io.FileInputStream throwClassCastException() + /// The returned object must be released after use, by calling the [release] method. + jni.JObject throwClassCastException() { + return const jni.JObjectType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_throwClassCastException, + jni.JniCallType.objectType, []).object); + } + + static final _id_throwArrayIndexException = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"throwArrayIndexException", r"()I"); + + /// from: public int throwArrayIndexException() + int throwArrayIndexException() { + return jni.Jni.accessors.callMethodWithArgs(reference, + _id_throwArrayIndexException, jni.JniCallType.intType, []).integer; + } + + static final _id_throwArithmeticException = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"throwArithmeticException", r"()I"); + + /// from: public int throwArithmeticException() + int throwArithmeticException() { + return jni.Jni.accessors.callMethodWithArgs(reference, + _id_throwArithmeticException, jni.JniCallType.intType, []).integer; + } + + static final _id_throwLoremIpsum = jni.Jni.accessors + .getStaticMethodIDOf(_class.reference, r"throwLoremIpsum", r"()V"); + + /// from: static public void throwLoremIpsum() + static void throwLoremIpsum() { + return jni.Jni.accessors.callStaticMethodWithArgs(_class.reference, + _id_throwLoremIpsum, jni.JniCallType.voidType, []).check(); + } +} + +final class $ExceptionsType extends jni.JObjType { + const $ExceptionsType(); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/simple_package/Exceptions;"; + + @override + Exceptions fromRef(jni.JObjectPtr ref) => Exceptions.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($ExceptionsType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($ExceptionsType) && other is $ExceptionsType; + } +} + +/// from: com.github.dart_lang.jnigen.simple_package.Fields +class Fields extends jni.JObject { + @override + late final jni.JObjType $type = type; + + Fields.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = + jni.Jni.findJClass(r"com/github/dart_lang/jnigen/simple_package/Fields"); + + /// The type which includes information such as the signature of this class. + static const type = $FieldsType(); + static final _id_amount = jni.Jni.accessors.getStaticFieldIDOf( + _class.reference, + r"amount", + r"I", + ); + + /// from: static public int amount + static int get amount => jni.Jni.accessors + .getStaticField(_class.reference, _id_amount, jni.JniCallType.intType) + .integer; + + /// from: static public int amount + static set amount(int value) => + jni.Jni.env.SetStaticIntField(_class.reference, _id_amount, value); + + static final _id_pi = jni.Jni.accessors.getStaticFieldIDOf( + _class.reference, + r"pi", + r"D", + ); + + /// from: static public double pi + static double get pi => jni.Jni.accessors + .getStaticField(_class.reference, _id_pi, jni.JniCallType.doubleType) + .doubleFloat; + + /// from: static public double pi + static set pi(double value) => + jni.Jni.env.SetStaticDoubleField(_class.reference, _id_pi, value); + + static final _id_asterisk = jni.Jni.accessors.getStaticFieldIDOf( + _class.reference, + r"asterisk", + r"C", + ); + + /// from: static public char asterisk + static int get asterisk => jni.Jni.accessors + .getStaticField(_class.reference, _id_asterisk, jni.JniCallType.charType) + .char; + + /// from: static public char asterisk + static set asterisk(int value) => + jni.Jni.env.SetStaticCharField(_class.reference, _id_asterisk, value); + + static final _id_name = jni.Jni.accessors.getStaticFieldIDOf( + _class.reference, + r"name", + r"Ljava/lang/String;", + ); + + /// from: static public java.lang.String name + /// The returned object must be released after use, by calling the [release] method. + static jni.JString get name => const jni.JStringType().fromRef(jni + .Jni.accessors + .getStaticField(_class.reference, _id_name, jni.JniCallType.objectType) + .object); + + /// from: static public java.lang.String name + /// The returned object must be released after use, by calling the [release] method. + static set name(jni.JString value) => jni.Jni.env + .SetStaticObjectField(_class.reference, _id_name, value.reference); + + static final _id_i = jni.Jni.accessors.getFieldIDOf( + _class.reference, + r"i", + r"Ljava/lang/Integer;", + ); + + /// from: public java.lang.Integer i + /// The returned object must be released after use, by calling the [release] method. + jni.JInteger get i => const jni.JIntegerType().fromRef(jni.Jni.accessors + .getField(reference, _id_i, jni.JniCallType.objectType) + .object); + + /// from: public java.lang.Integer i + /// The returned object must be released after use, by calling the [release] method. + set i(jni.JInteger value) => + jni.Jni.env.SetObjectField(reference, _id_i, value.reference); + + static final _id_trillion = jni.Jni.accessors.getFieldIDOf( + _class.reference, + r"trillion", + r"J", + ); + + /// from: public long trillion + int get trillion => jni.Jni.accessors + .getField(reference, _id_trillion, jni.JniCallType.longType) + .long; + + /// from: public long trillion + set trillion(int value) => + jni.Jni.env.SetLongField(reference, _id_trillion, value); + + static final _id_isAchillesDead = jni.Jni.accessors.getFieldIDOf( + _class.reference, + r"isAchillesDead", + r"Z", + ); + + /// from: public boolean isAchillesDead + bool get isAchillesDead => jni.Jni.accessors + .getField(reference, _id_isAchillesDead, jni.JniCallType.booleanType) + .boolean; + + /// from: public boolean isAchillesDead + set isAchillesDead(bool value) => + jni.Jni.env.SetBooleanField(reference, _id_isAchillesDead, value ? 1 : 0); + + static final _id_bestFighterInGreece = jni.Jni.accessors.getFieldIDOf( + _class.reference, + r"bestFighterInGreece", + r"Ljava/lang/String;", + ); + + /// from: public java.lang.String bestFighterInGreece + /// The returned object must be released after use, by calling the [release] method. + jni.JString get bestFighterInGreece => const jni.JStringType().fromRef(jni + .Jni.accessors + .getField(reference, _id_bestFighterInGreece, jni.JniCallType.objectType) + .object); + + /// from: public java.lang.String bestFighterInGreece + /// The returned object must be released after use, by calling the [release] method. + set bestFighterInGreece(jni.JString value) => jni.Jni.env + .SetObjectField(reference, _id_bestFighterInGreece, value.reference); + + static final _id_random = jni.Jni.accessors.getFieldIDOf( + _class.reference, + r"random", + r"Ljava/util/Random;", + ); + + /// from: public java.util.Random random + /// The returned object must be released after use, by calling the [release] method. + jni.JObject get random => const jni.JObjectType().fromRef(jni.Jni.accessors + .getField(reference, _id_random, jni.JniCallType.objectType) + .object); + + /// from: public java.util.Random random + /// The returned object must be released after use, by calling the [release] method. + set random(jni.JObject value) => + jni.Jni.env.SetObjectField(reference, _id_random, value.reference); + + static final _id_euroSymbol = jni.Jni.accessors.getStaticFieldIDOf( + _class.reference, + r"euroSymbol", + r"C", + ); + + /// from: static public char euroSymbol + static int get euroSymbol => jni.Jni.accessors + .getStaticField( + _class.reference, _id_euroSymbol, jni.JniCallType.charType) + .char; + + /// from: static public char euroSymbol + static set euroSymbol(int value) => + jni.Jni.env.SetStaticCharField(_class.reference, _id_euroSymbol, value); + + static final _id_new0 = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"", r"()V"); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory Fields() { + return Fields.fromRef(jni.Jni.accessors + .newObjectWithArgs(_class.reference, _id_new0, []).object); + } +} + +final class $FieldsType extends jni.JObjType { + const $FieldsType(); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/simple_package/Fields;"; + + @override + Fields fromRef(jni.JObjectPtr ref) => Fields.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($FieldsType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($FieldsType) && other is $FieldsType; + } +} + +/// from: com.github.dart_lang.jnigen.simple_package.Fields$Nested +class Fields_Nested extends jni.JObject { + @override + late final jni.JObjType $type = type; + + Fields_Nested.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = jni.Jni.findJClass( + r"com/github/dart_lang/jnigen/simple_package/Fields$Nested"); + + /// The type which includes information such as the signature of this class. + static const type = $Fields_NestedType(); + static final _id_hundred = jni.Jni.accessors.getFieldIDOf( + _class.reference, + r"hundred", + r"J", + ); + + /// from: public long hundred + int get hundred => jni.Jni.accessors + .getField(reference, _id_hundred, jni.JniCallType.longType) + .long; + + /// from: public long hundred + set hundred(int value) => + jni.Jni.env.SetLongField(reference, _id_hundred, value); + + static final _id_BEST_GOD = jni.Jni.accessors.getStaticFieldIDOf( + _class.reference, + r"BEST_GOD", + r"Ljava/lang/String;", + ); + + /// from: static public java.lang.String BEST_GOD + /// The returned object must be released after use, by calling the [release] method. + static jni.JString get BEST_GOD => + const jni.JStringType().fromRef(jni.Jni.accessors + .getStaticField( + _class.reference, _id_BEST_GOD, jni.JniCallType.objectType) + .object); + + /// from: static public java.lang.String BEST_GOD + /// The returned object must be released after use, by calling the [release] method. + static set BEST_GOD(jni.JString value) => jni.Jni.env + .SetStaticObjectField(_class.reference, _id_BEST_GOD, value.reference); + + static final _id_new0 = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"", r"()V"); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory Fields_Nested() { + return Fields_Nested.fromRef(jni.Jni.accessors + .newObjectWithArgs(_class.reference, _id_new0, []).object); + } +} + +final class $Fields_NestedType extends jni.JObjType { + const $Fields_NestedType(); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/simple_package/Fields$Nested;"; + + @override + Fields_Nested fromRef(jni.JObjectPtr ref) => Fields_Nested.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($Fields_NestedType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($Fields_NestedType) && + other is $Fields_NestedType; + } +} + +/// from: com.github.dart_lang.jnigen.pkg2.C2 +class C2 extends jni.JObject { + @override + late final jni.JObjType $type = type; + + C2.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = + jni.Jni.findJClass(r"com/github/dart_lang/jnigen/pkg2/C2"); + + /// The type which includes information such as the signature of this class. + static const type = $C2Type(); + static final _id_CONSTANT = jni.Jni.accessors.getStaticFieldIDOf( + _class.reference, + r"CONSTANT", + r"I", + ); + + /// from: static public int CONSTANT + static int get CONSTANT => jni.Jni.accessors + .getStaticField(_class.reference, _id_CONSTANT, jni.JniCallType.intType) + .integer; + + /// from: static public int CONSTANT + static set CONSTANT(int value) => + jni.Jni.env.SetStaticIntField(_class.reference, _id_CONSTANT, value); + + static final _id_new0 = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"", r"()V"); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory C2() { + return C2.fromRef(jni.Jni.accessors + .newObjectWithArgs(_class.reference, _id_new0, []).object); + } +} + +final class $C2Type extends jni.JObjType { + const $C2Type(); + + @override + String get signature => r"Lcom/github/dart_lang/jnigen/pkg2/C2;"; + + @override + C2 fromRef(jni.JObjectPtr ref) => C2.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($C2Type).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($C2Type) && other is $C2Type; + } +} + +/// from: com.github.dart_lang.jnigen.pkg2.Example +class Example1 extends jni.JObject { + @override + late final jni.JObjType $type = type; + + Example1.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = + jni.Jni.findJClass(r"com/github/dart_lang/jnigen/pkg2/Example"); + + /// The type which includes information such as the signature of this class. + static const type = $Example1Type(); + static final _id_new0 = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"", r"()V"); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory Example1() { + return Example1.fromRef(jni.Jni.accessors + .newObjectWithArgs(_class.reference, _id_new0, []).object); + } + + static final _id_whichExample = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"whichExample", r"()I"); + + /// from: public int whichExample() + int whichExample() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_whichExample, jni.JniCallType.intType, []).integer; + } +} + +final class $Example1Type extends jni.JObjType { + const $Example1Type(); + + @override + String get signature => r"Lcom/github/dart_lang/jnigen/pkg2/Example;"; + + @override + Example1 fromRef(jni.JObjectPtr ref) => Example1.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($Example1Type).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($Example1Type) && other is $Example1Type; + } +} + +/// from: com.github.dart_lang.jnigen.generics.GenericTypeParams +class GenericTypeParams<$S extends jni.JObject, $K extends jni.JObject> + extends jni.JObject { + @override + late final jni.JObjType> $type = type(S, K); + + final jni.JObjType<$S> S; + final jni.JObjType<$K> K; + + GenericTypeParams.fromRef( + this.S, + this.K, + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = jni.Jni.findJClass( + r"com/github/dart_lang/jnigen/generics/GenericTypeParams"); + + /// The type which includes information such as the signature of this class. + static $GenericTypeParamsType<$S, $K> + type<$S extends jni.JObject, $K extends jni.JObject>( + jni.JObjType<$S> S, + jni.JObjType<$K> K, + ) { + return $GenericTypeParamsType( + S, + K, + ); + } + + static final _id_new0 = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"", r"()V"); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory GenericTypeParams({ + required jni.JObjType<$S> S, + required jni.JObjType<$K> K, + }) { + return GenericTypeParams.fromRef( + S, + K, + jni.Jni.accessors + .newObjectWithArgs(_class.reference, _id_new0, []).object); + } +} + +final class $GenericTypeParamsType<$S extends jni.JObject, + $K extends jni.JObject> extends jni.JObjType> { + final jni.JObjType<$S> S; + final jni.JObjType<$K> K; + + const $GenericTypeParamsType( + this.S, + this.K, + ); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/generics/GenericTypeParams;"; + + @override + GenericTypeParams<$S, $K> fromRef(jni.JObjectPtr ref) => + GenericTypeParams.fromRef(S, K, ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => Object.hash($GenericTypeParamsType, S, K); + + @override + bool operator ==(Object other) { + return other.runtimeType == ($GenericTypeParamsType<$S, $K>) && + other is $GenericTypeParamsType<$S, $K> && + S == other.S && + K == other.K; + } +} + +/// from: com.github.dart_lang.jnigen.generics.GrandParent +class GrandParent<$T extends jni.JObject> extends jni.JObject { + @override + late final jni.JObjType> $type = type(T); + + final jni.JObjType<$T> T; + + GrandParent.fromRef( + this.T, + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = + jni.Jni.findJClass(r"com/github/dart_lang/jnigen/generics/GrandParent"); + + /// The type which includes information such as the signature of this class. + static $GrandParentType<$T> type<$T extends jni.JObject>( + jni.JObjType<$T> T, + ) { + return $GrandParentType( + T, + ); + } + + static final _id_value = jni.Jni.accessors.getFieldIDOf( + _class.reference, + r"value", + r"Ljava/lang/Object;", + ); + + /// from: public T value + /// The returned object must be released after use, by calling the [release] method. + $T get value => T.fromRef(jni.Jni.accessors + .getField(reference, _id_value, jni.JniCallType.objectType) + .object); + + /// from: public T value + /// The returned object must be released after use, by calling the [release] method. + set value($T value) => + jni.Jni.env.SetObjectField(reference, _id_value, value.reference); + + static final _id_new0 = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"", r"(Ljava/lang/Object;)V"); + + /// from: public void (T value) + /// The returned object must be released after use, by calling the [release] method. + factory GrandParent( + $T value, { + jni.JObjType<$T>? T, + }) { + T ??= jni.lowestCommonSuperType([ + value.$type, + ]) as jni.JObjType<$T>; + return GrandParent.fromRef( + T, + jni.Jni.accessors.newObjectWithArgs( + _class.reference, _id_new0, [value.reference]).object); + } + + static final _id_stringParent = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"stringParent", + r"()Lcom/github/dart_lang/jnigen/generics/GrandParent$Parent;"); + + /// from: public com.github.dart_lang.jnigen.generics.GrandParent.Parent stringParent() + /// The returned object must be released after use, by calling the [release] method. + GrandParent_Parent stringParent() { + return const $GrandParent_ParentType(jni.JObjectType(), jni.JStringType()) + .fromRef(jni.Jni.accessors.callMethodWithArgs(reference, + _id_stringParent, jni.JniCallType.objectType, []).object); + } + + static final _id_varParent = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"varParent", + r"(Ljava/lang/Object;)Lcom/github/dart_lang/jnigen/generics/GrandParent$Parent;"); + + /// from: public com.github.dart_lang.jnigen.generics.GrandParent.Parent varParent(S nestedValue) + /// The returned object must be released after use, by calling the [release] method. + GrandParent_Parent varParent<$S extends jni.JObject>( + $S nestedValue, { + jni.JObjType<$S>? S, + }) { + S ??= jni.lowestCommonSuperType([ + nestedValue.$type, + ]) as jni.JObjType<$S>; + return $GrandParent_ParentType(const jni.JObjectType(), S).fromRef( + jni.Jni.accessors.callMethodWithArgs(reference, _id_varParent, + jni.JniCallType.objectType, [nestedValue.reference]).object); + } + + static final _id_stringStaticParent = jni.Jni.accessors.getStaticMethodIDOf( + _class.reference, + r"stringStaticParent", + r"()Lcom/github/dart_lang/jnigen/generics/GrandParent$StaticParent;"); + + /// from: static public com.github.dart_lang.jnigen.generics.GrandParent.StaticParent stringStaticParent() + /// The returned object must be released after use, by calling the [release] method. + static GrandParent_StaticParent stringStaticParent() { + return const $GrandParent_StaticParentType(jni.JStringType()).fromRef( + jni.Jni.accessors.callStaticMethodWithArgs(_class.reference, + _id_stringStaticParent, jni.JniCallType.objectType, []).object); + } + + static final _id_varStaticParent = jni.Jni.accessors.getStaticMethodIDOf( + _class.reference, + r"varStaticParent", + r"(Ljava/lang/Object;)Lcom/github/dart_lang/jnigen/generics/GrandParent$StaticParent;"); + + /// from: static public com.github.dart_lang.jnigen.generics.GrandParent.StaticParent varStaticParent(S value) + /// The returned object must be released after use, by calling the [release] method. + static GrandParent_StaticParent<$S> varStaticParent<$S extends jni.JObject>( + $S value, { + jni.JObjType<$S>? S, + }) { + S ??= jni.lowestCommonSuperType([ + value.$type, + ]) as jni.JObjType<$S>; + return $GrandParent_StaticParentType(S).fromRef(jni.Jni.accessors + .callStaticMethodWithArgs(_class.reference, _id_varStaticParent, + jni.JniCallType.objectType, [value.reference]).object); + } + + static final _id_staticParentWithSameType = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"staticParentWithSameType", + r"()Lcom/github/dart_lang/jnigen/generics/GrandParent$StaticParent;"); + + /// from: public com.github.dart_lang.jnigen.generics.GrandParent.StaticParent staticParentWithSameType() + /// The returned object must be released after use, by calling the [release] method. + GrandParent_StaticParent<$T> staticParentWithSameType() { + return $GrandParent_StaticParentType(T).fromRef(jni.Jni.accessors + .callMethodWithArgs(reference, _id_staticParentWithSameType, + jni.JniCallType.objectType, []).object); + } +} + +final class $GrandParentType<$T extends jni.JObject> + extends jni.JObjType> { + final jni.JObjType<$T> T; + + const $GrandParentType( + this.T, + ); + + @override + String get signature => r"Lcom/github/dart_lang/jnigen/generics/GrandParent;"; + + @override + GrandParent<$T> fromRef(jni.JObjectPtr ref) => GrandParent.fromRef(T, ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => Object.hash($GrandParentType, T); + + @override + bool operator ==(Object other) { + return other.runtimeType == ($GrandParentType<$T>) && + other is $GrandParentType<$T> && + T == other.T; + } +} + +/// from: com.github.dart_lang.jnigen.generics.GrandParent$Parent +class GrandParent_Parent<$T extends jni.JObject, $S extends jni.JObject> + extends jni.JObject { + @override + late final jni.JObjType> $type = type(T, S); + + final jni.JObjType<$T> T; + final jni.JObjType<$S> S; + + GrandParent_Parent.fromRef( + this.T, + this.S, + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = jni.Jni.findJClass( + r"com/github/dart_lang/jnigen/generics/GrandParent$Parent"); + + /// The type which includes information such as the signature of this class. + static $GrandParent_ParentType<$T, $S> + type<$T extends jni.JObject, $S extends jni.JObject>( + jni.JObjType<$T> T, + jni.JObjType<$S> S, + ) { + return $GrandParent_ParentType( + T, + S, + ); + } + + static final _id_parentValue = jni.Jni.accessors.getFieldIDOf( + _class.reference, + r"parentValue", + r"Ljava/lang/Object;", + ); + + /// from: public T parentValue + /// The returned object must be released after use, by calling the [release] method. + $T get parentValue => T.fromRef(jni.Jni.accessors + .getField(reference, _id_parentValue, jni.JniCallType.objectType) + .object); + + /// from: public T parentValue + /// The returned object must be released after use, by calling the [release] method. + set parentValue($T value) => + jni.Jni.env.SetObjectField(reference, _id_parentValue, value.reference); + + static final _id_value = jni.Jni.accessors.getFieldIDOf( + _class.reference, + r"value", + r"Ljava/lang/Object;", + ); + + /// from: public S value + /// The returned object must be released after use, by calling the [release] method. + $S get value => S.fromRef(jni.Jni.accessors + .getField(reference, _id_value, jni.JniCallType.objectType) + .object); + + /// from: public S value + /// The returned object must be released after use, by calling the [release] method. + set value($S value) => + jni.Jni.env.SetObjectField(reference, _id_value, value.reference); + + static final _id_new0 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"", + r"(Lcom/github/dart_lang/jnigen/generics/GrandParent;Ljava/lang/Object;)V"); + + /// from: public void (com.github.dart_lang.jnigen.generics.GrandParent $parent, S newValue) + /// The returned object must be released after use, by calling the [release] method. + factory GrandParent_Parent( + GrandParent<$T> $parent, + $S newValue, { + jni.JObjType<$T>? T, + jni.JObjType<$S>? S, + }) { + T ??= jni.lowestCommonSuperType([ + ($parent.$type as $GrandParentType).T, + ]) as jni.JObjType<$T>; + S ??= jni.lowestCommonSuperType([ + newValue.$type, + ]) as jni.JObjType<$S>; + return GrandParent_Parent.fromRef( + T, + S, + jni.Jni.accessors.newObjectWithArgs(_class.reference, _id_new0, + [$parent.reference, newValue.reference]).object); + } +} + +final class $GrandParent_ParentType<$T extends jni.JObject, + $S extends jni.JObject> extends jni.JObjType> { + final jni.JObjType<$T> T; + final jni.JObjType<$S> S; + + const $GrandParent_ParentType( + this.T, + this.S, + ); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/generics/GrandParent$Parent;"; + + @override + GrandParent_Parent<$T, $S> fromRef(jni.JObjectPtr ref) => + GrandParent_Parent.fromRef(T, S, ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => Object.hash($GrandParent_ParentType, T, S); + + @override + bool operator ==(Object other) { + return other.runtimeType == ($GrandParent_ParentType<$T, $S>) && + other is $GrandParent_ParentType<$T, $S> && + T == other.T && + S == other.S; + } +} + +/// from: com.github.dart_lang.jnigen.generics.GrandParent$Parent$Child +class GrandParent_Parent_Child<$T extends jni.JObject, $S extends jni.JObject, + $U extends jni.JObject> extends jni.JObject { + @override + late final jni.JObjType> $type = + type(T, S, U); + + final jni.JObjType<$T> T; + final jni.JObjType<$S> S; + final jni.JObjType<$U> U; + + GrandParent_Parent_Child.fromRef( + this.T, + this.S, + this.U, + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = jni.Jni.findJClass( + r"com/github/dart_lang/jnigen/generics/GrandParent$Parent$Child"); + + /// The type which includes information such as the signature of this class. + static $GrandParent_Parent_ChildType<$T, $S, $U> type<$T extends jni.JObject, + $S extends jni.JObject, $U extends jni.JObject>( + jni.JObjType<$T> T, + jni.JObjType<$S> S, + jni.JObjType<$U> U, + ) { + return $GrandParent_Parent_ChildType( + T, + S, + U, + ); + } + + static final _id_grandParentValue = jni.Jni.accessors.getFieldIDOf( + _class.reference, + r"grandParentValue", + r"Ljava/lang/Object;", + ); + + /// from: public T grandParentValue + /// The returned object must be released after use, by calling the [release] method. + $T get grandParentValue => T.fromRef(jni.Jni.accessors + .getField(reference, _id_grandParentValue, jni.JniCallType.objectType) + .object); + + /// from: public T grandParentValue + /// The returned object must be released after use, by calling the [release] method. + set grandParentValue($T value) => jni.Jni.env + .SetObjectField(reference, _id_grandParentValue, value.reference); + + static final _id_parentValue = jni.Jni.accessors.getFieldIDOf( + _class.reference, + r"parentValue", + r"Ljava/lang/Object;", + ); + + /// from: public S parentValue + /// The returned object must be released after use, by calling the [release] method. + $S get parentValue => S.fromRef(jni.Jni.accessors + .getField(reference, _id_parentValue, jni.JniCallType.objectType) + .object); + + /// from: public S parentValue + /// The returned object must be released after use, by calling the [release] method. + set parentValue($S value) => + jni.Jni.env.SetObjectField(reference, _id_parentValue, value.reference); + + static final _id_value = jni.Jni.accessors.getFieldIDOf( + _class.reference, + r"value", + r"Ljava/lang/Object;", + ); + + /// from: public U value + /// The returned object must be released after use, by calling the [release] method. + $U get value => U.fromRef(jni.Jni.accessors + .getField(reference, _id_value, jni.JniCallType.objectType) + .object); + + /// from: public U value + /// The returned object must be released after use, by calling the [release] method. + set value($U value) => + jni.Jni.env.SetObjectField(reference, _id_value, value.reference); + + static final _id_new0 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"", + r"(Lcom/github/dart_lang/jnigen/generics/GrandParent$Parent;Ljava/lang/Object;)V"); + + /// from: public void (com.github.dart_lang.jnigen.generics.GrandParent$Parent $parent, U newValue) + /// The returned object must be released after use, by calling the [release] method. + factory GrandParent_Parent_Child( + GrandParent_Parent<$T, $S> $parent, + $U newValue, { + jni.JObjType<$T>? T, + jni.JObjType<$S>? S, + jni.JObjType<$U>? U, + }) { + T ??= jni.lowestCommonSuperType([ + ($parent.$type as $GrandParent_ParentType).T, + ]) as jni.JObjType<$T>; + S ??= jni.lowestCommonSuperType([ + ($parent.$type as $GrandParent_ParentType).S, + ]) as jni.JObjType<$S>; + U ??= jni.lowestCommonSuperType([ + newValue.$type, + ]) as jni.JObjType<$U>; + return GrandParent_Parent_Child.fromRef( + T, + S, + U, + jni.Jni.accessors.newObjectWithArgs(_class.reference, _id_new0, + [$parent.reference, newValue.reference]).object); + } +} + +final class $GrandParent_Parent_ChildType<$T extends jni.JObject, + $S extends jni.JObject, $U extends jni.JObject> + extends jni.JObjType> { + final jni.JObjType<$T> T; + final jni.JObjType<$S> S; + final jni.JObjType<$U> U; + + const $GrandParent_Parent_ChildType( + this.T, + this.S, + this.U, + ); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/generics/GrandParent$Parent$Child;"; + + @override + GrandParent_Parent_Child<$T, $S, $U> fromRef(jni.JObjectPtr ref) => + GrandParent_Parent_Child.fromRef(T, S, U, ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => Object.hash($GrandParent_Parent_ChildType, T, S, U); + + @override + bool operator ==(Object other) { + return other.runtimeType == ($GrandParent_Parent_ChildType<$T, $S, $U>) && + other is $GrandParent_Parent_ChildType<$T, $S, $U> && + T == other.T && + S == other.S && + U == other.U; + } +} + +/// from: com.github.dart_lang.jnigen.generics.GrandParent$StaticParent +class GrandParent_StaticParent<$S extends jni.JObject> extends jni.JObject { + @override + late final jni.JObjType> $type = type(S); + + final jni.JObjType<$S> S; + + GrandParent_StaticParent.fromRef( + this.S, + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = jni.Jni.findJClass( + r"com/github/dart_lang/jnigen/generics/GrandParent$StaticParent"); + + /// The type which includes information such as the signature of this class. + static $GrandParent_StaticParentType<$S> type<$S extends jni.JObject>( + jni.JObjType<$S> S, + ) { + return $GrandParent_StaticParentType( + S, + ); + } + + static final _id_value = jni.Jni.accessors.getFieldIDOf( + _class.reference, + r"value", + r"Ljava/lang/Object;", + ); + + /// from: public S value + /// The returned object must be released after use, by calling the [release] method. + $S get value => S.fromRef(jni.Jni.accessors + .getField(reference, _id_value, jni.JniCallType.objectType) + .object); + + /// from: public S value + /// The returned object must be released after use, by calling the [release] method. + set value($S value) => + jni.Jni.env.SetObjectField(reference, _id_value, value.reference); + + static final _id_new0 = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"", r"(Ljava/lang/Object;)V"); + + /// from: public void (S value) + /// The returned object must be released after use, by calling the [release] method. + factory GrandParent_StaticParent( + $S value, { + jni.JObjType<$S>? S, + }) { + S ??= jni.lowestCommonSuperType([ + value.$type, + ]) as jni.JObjType<$S>; + return GrandParent_StaticParent.fromRef( + S, + jni.Jni.accessors.newObjectWithArgs( + _class.reference, _id_new0, [value.reference]).object); + } +} + +final class $GrandParent_StaticParentType<$S extends jni.JObject> + extends jni.JObjType> { + final jni.JObjType<$S> S; + + const $GrandParent_StaticParentType( + this.S, + ); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/generics/GrandParent$StaticParent;"; + + @override + GrandParent_StaticParent<$S> fromRef(jni.JObjectPtr ref) => + GrandParent_StaticParent.fromRef(S, ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => Object.hash($GrandParent_StaticParentType, S); + + @override + bool operator ==(Object other) { + return other.runtimeType == ($GrandParent_StaticParentType<$S>) && + other is $GrandParent_StaticParentType<$S> && + S == other.S; + } +} + +/// from: com.github.dart_lang.jnigen.generics.GrandParent$StaticParent$Child +class GrandParent_StaticParent_Child<$S extends jni.JObject, + $U extends jni.JObject> extends jni.JObject { + @override + late final jni.JObjType> $type = + type(S, U); + + final jni.JObjType<$S> S; + final jni.JObjType<$U> U; + + GrandParent_StaticParent_Child.fromRef( + this.S, + this.U, + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = jni.Jni.findJClass( + r"com/github/dart_lang/jnigen/generics/GrandParent$StaticParent$Child"); + + /// The type which includes information such as the signature of this class. + static $GrandParent_StaticParent_ChildType<$S, $U> + type<$S extends jni.JObject, $U extends jni.JObject>( + jni.JObjType<$S> S, + jni.JObjType<$U> U, + ) { + return $GrandParent_StaticParent_ChildType( + S, + U, + ); + } + + static final _id_parentValue = jni.Jni.accessors.getFieldIDOf( + _class.reference, + r"parentValue", + r"Ljava/lang/Object;", + ); + + /// from: public S parentValue + /// The returned object must be released after use, by calling the [release] method. + $S get parentValue => S.fromRef(jni.Jni.accessors + .getField(reference, _id_parentValue, jni.JniCallType.objectType) + .object); + + /// from: public S parentValue + /// The returned object must be released after use, by calling the [release] method. + set parentValue($S value) => + jni.Jni.env.SetObjectField(reference, _id_parentValue, value.reference); + + static final _id_value = jni.Jni.accessors.getFieldIDOf( + _class.reference, + r"value", + r"Ljava/lang/Object;", + ); + + /// from: public U value + /// The returned object must be released after use, by calling the [release] method. + $U get value => U.fromRef(jni.Jni.accessors + .getField(reference, _id_value, jni.JniCallType.objectType) + .object); + + /// from: public U value + /// The returned object must be released after use, by calling the [release] method. + set value($U value) => + jni.Jni.env.SetObjectField(reference, _id_value, value.reference); + + static final _id_new0 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"", + r"(Lcom/github/dart_lang/jnigen/generics/GrandParent$StaticParent;Ljava/lang/Object;Ljava/lang/Object;)V"); + + /// from: public void (com.github.dart_lang.jnigen.generics.GrandParent$StaticParent $parent, S parentValue, U value) + /// The returned object must be released after use, by calling the [release] method. + factory GrandParent_StaticParent_Child( + GrandParent_StaticParent<$S> $parent, + $S parentValue, + $U value, { + jni.JObjType<$S>? S, + jni.JObjType<$U>? U, + }) { + S ??= jni.lowestCommonSuperType([ + parentValue.$type, + ($parent.$type as $GrandParent_StaticParentType).S, + ]) as jni.JObjType<$S>; + U ??= jni.lowestCommonSuperType([ + value.$type, + ]) as jni.JObjType<$U>; + return GrandParent_StaticParent_Child.fromRef( + S, + U, + jni.Jni.accessors.newObjectWithArgs(_class.reference, _id_new0, [ + $parent.reference, + parentValue.reference, + value.reference + ]).object); + } +} + +final class $GrandParent_StaticParent_ChildType<$S extends jni.JObject, + $U extends jni.JObject> + extends jni.JObjType> { + final jni.JObjType<$S> S; + final jni.JObjType<$U> U; + + const $GrandParent_StaticParent_ChildType( + this.S, + this.U, + ); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/generics/GrandParent$StaticParent$Child;"; + + @override + GrandParent_StaticParent_Child<$S, $U> fromRef(jni.JObjectPtr ref) => + GrandParent_StaticParent_Child.fromRef(S, U, ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => Object.hash($GrandParent_StaticParent_ChildType, S, U); + + @override + bool operator ==(Object other) { + return other.runtimeType == ($GrandParent_StaticParent_ChildType<$S, $U>) && + other is $GrandParent_StaticParent_ChildType<$S, $U> && + S == other.S && + U == other.U; + } +} + +/// from: com.github.dart_lang.jnigen.generics.MyMap +class MyMap<$K extends jni.JObject, $V extends jni.JObject> + extends jni.JObject { + @override + late final jni.JObjType> $type = type(K, V); + + final jni.JObjType<$K> K; + final jni.JObjType<$V> V; + + MyMap.fromRef( + this.K, + this.V, + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = + jni.Jni.findJClass(r"com/github/dart_lang/jnigen/generics/MyMap"); + + /// The type which includes information such as the signature of this class. + static $MyMapType<$K, $V> + type<$K extends jni.JObject, $V extends jni.JObject>( + jni.JObjType<$K> K, + jni.JObjType<$V> V, + ) { + return $MyMapType( + K, + V, + ); + } + + static final _id_new0 = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"", r"()V"); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory MyMap({ + required jni.JObjType<$K> K, + required jni.JObjType<$V> V, + }) { + return MyMap.fromRef( + K, + V, + jni.Jni.accessors + .newObjectWithArgs(_class.reference, _id_new0, []).object); + } + + static final _id_get0 = jni.Jni.accessors.getMethodIDOf( + _class.reference, r"get", r"(Ljava/lang/Object;)Ljava/lang/Object;"); + + /// from: public V get(K key) + /// The returned object must be released after use, by calling the [release] method. + $V get0( + $K key, + ) { + return V.fromRef(jni.Jni.accessors.callMethodWithArgs(reference, _id_get0, + jni.JniCallType.objectType, [key.reference]).object); + } + + static final _id_put = jni.Jni.accessors.getMethodIDOf(_class.reference, + r"put", r"(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); + + /// from: public V put(K key, V value) + /// The returned object must be released after use, by calling the [release] method. + $V put( + $K key, + $V value, + ) { + return V.fromRef(jni.Jni.accessors.callMethodWithArgs(reference, _id_put, + jni.JniCallType.objectType, [key.reference, value.reference]).object); + } + + static final _id_entryStack = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"entryStack", + r"()Lcom/github/dart_lang/jnigen/generics/MyStack;"); + + /// from: public com.github.dart_lang.jnigen.generics.MyStack.MyEntry> entryStack() + /// The returned object must be released after use, by calling the [release] method. + MyStack> entryStack() { + return const $MyStackType( + $MyMap_MyEntryType(jni.JObjectType(), jni.JObjectType())) + .fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, _id_entryStack, jni.JniCallType.objectType, []).object); + } +} + +final class $MyMapType<$K extends jni.JObject, $V extends jni.JObject> + extends jni.JObjType> { + final jni.JObjType<$K> K; + final jni.JObjType<$V> V; + + const $MyMapType( + this.K, + this.V, + ); + + @override + String get signature => r"Lcom/github/dart_lang/jnigen/generics/MyMap;"; + + @override + MyMap<$K, $V> fromRef(jni.JObjectPtr ref) => MyMap.fromRef(K, V, ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => Object.hash($MyMapType, K, V); + + @override + bool operator ==(Object other) { + return other.runtimeType == ($MyMapType<$K, $V>) && + other is $MyMapType<$K, $V> && + K == other.K && + V == other.V; + } +} + +/// from: com.github.dart_lang.jnigen.generics.MyMap$MyEntry +class MyMap_MyEntry<$K extends jni.JObject, $V extends jni.JObject> + extends jni.JObject { + @override + late final jni.JObjType> $type = type(K, V); + + final jni.JObjType<$K> K; + final jni.JObjType<$V> V; + + MyMap_MyEntry.fromRef( + this.K, + this.V, + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = + jni.Jni.findJClass(r"com/github/dart_lang/jnigen/generics/MyMap$MyEntry"); + + /// The type which includes information such as the signature of this class. + static $MyMap_MyEntryType<$K, $V> + type<$K extends jni.JObject, $V extends jni.JObject>( + jni.JObjType<$K> K, + jni.JObjType<$V> V, + ) { + return $MyMap_MyEntryType( + K, + V, + ); + } + + static final _id_key = jni.Jni.accessors.getFieldIDOf( + _class.reference, + r"key", + r"Ljava/lang/Object;", + ); + + /// from: public K key + /// The returned object must be released after use, by calling the [release] method. + $K get key => K.fromRef(jni.Jni.accessors + .getField(reference, _id_key, jni.JniCallType.objectType) + .object); + + /// from: public K key + /// The returned object must be released after use, by calling the [release] method. + set key($K value) => + jni.Jni.env.SetObjectField(reference, _id_key, value.reference); + + static final _id_value = jni.Jni.accessors.getFieldIDOf( + _class.reference, + r"value", + r"Ljava/lang/Object;", + ); + + /// from: public V value + /// The returned object must be released after use, by calling the [release] method. + $V get value => V.fromRef(jni.Jni.accessors + .getField(reference, _id_value, jni.JniCallType.objectType) + .object); + + /// from: public V value + /// The returned object must be released after use, by calling the [release] method. + set value($V value) => + jni.Jni.env.SetObjectField(reference, _id_value, value.reference); + + static final _id_new0 = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"", + r"(Lcom/github/dart_lang/jnigen/generics/MyMap;Ljava/lang/Object;Ljava/lang/Object;)V"); + + /// from: public void (com.github.dart_lang.jnigen.generics.MyMap $parent, K key, V value) + /// The returned object must be released after use, by calling the [release] method. + factory MyMap_MyEntry( + MyMap<$K, $V> $parent, + $K key, + $V value, { + jni.JObjType<$K>? K, + jni.JObjType<$V>? V, + }) { + K ??= jni.lowestCommonSuperType([ + key.$type, + ($parent.$type as $MyMapType).K, + ]) as jni.JObjType<$K>; + V ??= jni.lowestCommonSuperType([ + value.$type, + ($parent.$type as $MyMapType).V, + ]) as jni.JObjType<$V>; + return MyMap_MyEntry.fromRef( + K, + V, + jni.Jni.accessors.newObjectWithArgs(_class.reference, _id_new0, + [$parent.reference, key.reference, value.reference]).object); + } +} + +final class $MyMap_MyEntryType<$K extends jni.JObject, $V extends jni.JObject> + extends jni.JObjType> { + final jni.JObjType<$K> K; + final jni.JObjType<$V> V; + + const $MyMap_MyEntryType( + this.K, + this.V, + ); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/generics/MyMap$MyEntry;"; + + @override + MyMap_MyEntry<$K, $V> fromRef(jni.JObjectPtr ref) => + MyMap_MyEntry.fromRef(K, V, ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => Object.hash($MyMap_MyEntryType, K, V); + + @override + bool operator ==(Object other) { + return other.runtimeType == ($MyMap_MyEntryType<$K, $V>) && + other is $MyMap_MyEntryType<$K, $V> && + K == other.K && + V == other.V; + } +} + +/// from: com.github.dart_lang.jnigen.generics.MyStack +class MyStack<$T extends jni.JObject> extends jni.JObject { + @override + late final jni.JObjType> $type = type(T); + + final jni.JObjType<$T> T; + + MyStack.fromRef( + this.T, + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = + jni.Jni.findJClass(r"com/github/dart_lang/jnigen/generics/MyStack"); + + /// The type which includes information such as the signature of this class. + static $MyStackType<$T> type<$T extends jni.JObject>( + jni.JObjType<$T> T, + ) { + return $MyStackType( + T, + ); + } + + static final _id_new0 = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"", r"()V"); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory MyStack({ + required jni.JObjType<$T> T, + }) { + return MyStack.fromRef( + T, + jni.Jni.accessors + .newObjectWithArgs(_class.reference, _id_new0, []).object); + } + + static final _id_fromArray = jni.Jni.accessors.getStaticMethodIDOf( + _class.reference, + r"fromArray", + r"([Ljava/lang/Object;)Lcom/github/dart_lang/jnigen/generics/MyStack;"); + + /// from: static public com.github.dart_lang.jnigen.generics.MyStack fromArray(T[] arr) + /// The returned object must be released after use, by calling the [release] method. + static MyStack<$T> fromArray<$T extends jni.JObject>( + jni.JArray<$T> arr, { + jni.JObjType<$T>? T, + }) { + T ??= jni.lowestCommonSuperType([ + ((arr.$type as jni.JArrayType).elementType as jni.JObjType), + ]) as jni.JObjType<$T>; + return $MyStackType(T).fromRef(jni.Jni.accessors.callStaticMethodWithArgs( + _class.reference, + _id_fromArray, + jni.JniCallType.objectType, + [arr.reference]).object); + } + + static final _id_fromArrayOfArrayOfGrandParents = jni.Jni.accessors + .getStaticMethodIDOf(_class.reference, r"fromArrayOfArrayOfGrandParents", + r"([[Lcom/github/dart_lang/jnigen/generics/GrandParent;)Lcom/github/dart_lang/jnigen/generics/MyStack;"); + + /// from: static public com.github.dart_lang.jnigen.generics.MyStack fromArrayOfArrayOfGrandParents(com.github.dart_lang.jnigen.generics.GrandParent[][] arr) + /// The returned object must be released after use, by calling the [release] method. + static MyStack<$S> fromArrayOfArrayOfGrandParents<$S extends jni.JObject>( + jni.JArray>> arr, { + jni.JObjType<$S>? S, + }) { + S ??= jni.lowestCommonSuperType([ + (((((arr.$type as jni.JArrayType).elementType as jni.JObjType) + as jni.JArrayType) + .elementType as jni.JObjType) as $GrandParentType) + .T, + ]) as jni.JObjType<$S>; + return $MyStackType(S).fromRef(jni.Jni.accessors.callStaticMethodWithArgs( + _class.reference, + _id_fromArrayOfArrayOfGrandParents, + jni.JniCallType.objectType, + [arr.reference]).object); + } + + static final _id_of = jni.Jni.accessors.getStaticMethodIDOf(_class.reference, + r"of", r"()Lcom/github/dart_lang/jnigen/generics/MyStack;"); + + /// from: static public com.github.dart_lang.jnigen.generics.MyStack of() + /// The returned object must be released after use, by calling the [release] method. + static MyStack<$T> of<$T extends jni.JObject>({ + required jni.JObjType<$T> T, + }) { + return $MyStackType(T).fromRef(jni.Jni.accessors.callStaticMethodWithArgs( + _class.reference, _id_of, jni.JniCallType.objectType, []).object); + } + + static final _id_of1 = jni.Jni.accessors.getStaticMethodIDOf( + _class.reference, + r"of", + r"(Ljava/lang/Object;)Lcom/github/dart_lang/jnigen/generics/MyStack;"); + + /// from: static public com.github.dart_lang.jnigen.generics.MyStack of(T obj) + /// The returned object must be released after use, by calling the [release] method. + static MyStack<$T> of1<$T extends jni.JObject>( + $T obj, { + jni.JObjType<$T>? T, + }) { + T ??= jni.lowestCommonSuperType([ + obj.$type, + ]) as jni.JObjType<$T>; + return $MyStackType(T).fromRef(jni.Jni.accessors.callStaticMethodWithArgs( + _class.reference, + _id_of1, + jni.JniCallType.objectType, + [obj.reference]).object); + } + + static final _id_of2 = jni.Jni.accessors.getStaticMethodIDOf( + _class.reference, + r"of", + r"(Ljava/lang/Object;Ljava/lang/Object;)Lcom/github/dart_lang/jnigen/generics/MyStack;"); + + /// from: static public com.github.dart_lang.jnigen.generics.MyStack of(T obj, T obj2) + /// The returned object must be released after use, by calling the [release] method. + static MyStack<$T> of2<$T extends jni.JObject>( + $T obj, + $T obj2, { + jni.JObjType<$T>? T, + }) { + T ??= jni.lowestCommonSuperType([ + obj2.$type, + obj.$type, + ]) as jni.JObjType<$T>; + return $MyStackType(T).fromRef(jni.Jni.accessors.callStaticMethodWithArgs( + _class.reference, + _id_of2, + jni.JniCallType.objectType, + [obj.reference, obj2.reference]).object); + } + + static final _id_push = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"push", r"(Ljava/lang/Object;)V"); + + /// from: public void push(T item) + void push( + $T item, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_push, + jni.JniCallType.voidType, [item.reference]).check(); + } + + static final _id_pop = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"pop", r"()Ljava/lang/Object;"); + + /// from: public T pop() + /// The returned object must be released after use, by calling the [release] method. + $T pop() { + return T.fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, _id_pop, jni.JniCallType.objectType, []).object); + } + + static final _id_size = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"size", r"()I"); + + /// from: public int size() + int size() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_size, jni.JniCallType.intType, []).integer; + } +} + +final class $MyStackType<$T extends jni.JObject> + extends jni.JObjType> { + final jni.JObjType<$T> T; + + const $MyStackType( + this.T, + ); + + @override + String get signature => r"Lcom/github/dart_lang/jnigen/generics/MyStack;"; + + @override + MyStack<$T> fromRef(jni.JObjectPtr ref) => MyStack.fromRef(T, ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => Object.hash($MyStackType, T); + + @override + bool operator ==(Object other) { + return other.runtimeType == ($MyStackType<$T>) && + other is $MyStackType<$T> && + T == other.T; + } +} + +/// from: com.github.dart_lang.jnigen.generics.StringKeyedMap +class StringKeyedMap<$V extends jni.JObject> extends MyMap { + @override + late final jni.JObjType> $type = type(V); + + final jni.JObjType<$V> V; + + StringKeyedMap.fromRef( + this.V, + jni.JObjectPtr ref, + ) : super.fromRef(const jni.JStringType(), V, ref); + + static final _class = jni.Jni.findJClass( + r"com/github/dart_lang/jnigen/generics/StringKeyedMap"); + + /// The type which includes information such as the signature of this class. + static $StringKeyedMapType<$V> type<$V extends jni.JObject>( + jni.JObjType<$V> V, + ) { + return $StringKeyedMapType( + V, + ); + } + + static final _id_new0 = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"", r"()V"); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory StringKeyedMap({ + required jni.JObjType<$V> V, + }) { + return StringKeyedMap.fromRef( + V, + jni.Jni.accessors + .newObjectWithArgs(_class.reference, _id_new0, []).object); + } +} + +final class $StringKeyedMapType<$V extends jni.JObject> + extends jni.JObjType> { + final jni.JObjType<$V> V; + + const $StringKeyedMapType( + this.V, + ); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/generics/StringKeyedMap;"; + + @override + StringKeyedMap<$V> fromRef(jni.JObjectPtr ref) => + StringKeyedMap.fromRef(V, ref); + + @override + jni.JObjType get superType => $MyMapType(const jni.JStringType(), V); + + @override + final superCount = 2; + + @override + int get hashCode => Object.hash($StringKeyedMapType, V); + + @override + bool operator ==(Object other) { + return other.runtimeType == ($StringKeyedMapType<$V>) && + other is $StringKeyedMapType<$V> && + V == other.V; + } +} + +/// from: com.github.dart_lang.jnigen.generics.StringMap +class StringMap extends StringKeyedMap { + @override + late final jni.JObjType $type = type; + + StringMap.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(const jni.JStringType(), ref); + + static final _class = + jni.Jni.findJClass(r"com/github/dart_lang/jnigen/generics/StringMap"); + + /// The type which includes information such as the signature of this class. + static const type = $StringMapType(); + static final _id_new0 = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"", r"()V"); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory StringMap() { + return StringMap.fromRef(jni.Jni.accessors + .newObjectWithArgs(_class.reference, _id_new0, []).object); + } +} + +final class $StringMapType extends jni.JObjType { + const $StringMapType(); + + @override + String get signature => r"Lcom/github/dart_lang/jnigen/generics/StringMap;"; + + @override + StringMap fromRef(jni.JObjectPtr ref) => StringMap.fromRef(ref); + + @override + jni.JObjType get superType => const $StringKeyedMapType(jni.JStringType()); + + @override + final superCount = 3; + + @override + int get hashCode => ($StringMapType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($StringMapType) && other is $StringMapType; + } +} + +/// from: com.github.dart_lang.jnigen.generics.StringStack +class StringStack extends MyStack { + @override + late final jni.JObjType $type = type; + + StringStack.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(const jni.JStringType(), ref); + + static final _class = + jni.Jni.findJClass(r"com/github/dart_lang/jnigen/generics/StringStack"); + + /// The type which includes information such as the signature of this class. + static const type = $StringStackType(); + static final _id_new0 = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"", r"()V"); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory StringStack() { + return StringStack.fromRef(jni.Jni.accessors + .newObjectWithArgs(_class.reference, _id_new0, []).object); + } +} + +final class $StringStackType extends jni.JObjType { + const $StringStackType(); + + @override + String get signature => r"Lcom/github/dart_lang/jnigen/generics/StringStack;"; + + @override + StringStack fromRef(jni.JObjectPtr ref) => StringStack.fromRef(ref); + + @override + jni.JObjType get superType => const $MyStackType(jni.JStringType()); + + @override + final superCount = 2; + + @override + int get hashCode => ($StringStackType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($StringStackType) && other is $StringStackType; + } +} + +/// from: com.github.dart_lang.jnigen.generics.StringValuedMap +class StringValuedMap<$K extends jni.JObject> extends MyMap<$K, jni.JString> { + @override + late final jni.JObjType> $type = type(K); + + final jni.JObjType<$K> K; + + StringValuedMap.fromRef( + this.K, + jni.JObjectPtr ref, + ) : super.fromRef(K, const jni.JStringType(), ref); + + static final _class = jni.Jni.findJClass( + r"com/github/dart_lang/jnigen/generics/StringValuedMap"); + + /// The type which includes information such as the signature of this class. + static $StringValuedMapType<$K> type<$K extends jni.JObject>( + jni.JObjType<$K> K, + ) { + return $StringValuedMapType( + K, + ); + } + + static final _id_new0 = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"", r"()V"); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory StringValuedMap({ + required jni.JObjType<$K> K, + }) { + return StringValuedMap.fromRef( + K, + jni.Jni.accessors + .newObjectWithArgs(_class.reference, _id_new0, []).object); + } +} + +final class $StringValuedMapType<$K extends jni.JObject> + extends jni.JObjType> { + final jni.JObjType<$K> K; + + const $StringValuedMapType( + this.K, + ); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/generics/StringValuedMap;"; + + @override + StringValuedMap<$K> fromRef(jni.JObjectPtr ref) => + StringValuedMap.fromRef(K, ref); + + @override + jni.JObjType get superType => $MyMapType(K, const jni.JStringType()); + + @override + final superCount = 2; + + @override + int get hashCode => Object.hash($StringValuedMapType, K); + + @override + bool operator ==(Object other) { + return other.runtimeType == ($StringValuedMapType<$K>) && + other is $StringValuedMapType<$K> && + K == other.K; + } +} + +/// from: com.github.dart_lang.jnigen.interfaces.MyInterface +class MyInterface<$T extends jni.JObject> extends jni.JObject { + @override + late final jni.JObjType> $type = type(T); + + final jni.JObjType<$T> T; + + MyInterface.fromRef( + this.T, + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = + jni.Jni.findJClass(r"com/github/dart_lang/jnigen/interfaces/MyInterface"); + + /// The type which includes information such as the signature of this class. + static $MyInterfaceType<$T> type<$T extends jni.JObject>( + jni.JObjType<$T> T, + ) { + return $MyInterfaceType( + T, + ); + } + + static final _id_voidCallback = jni.Jni.accessors.getMethodIDOf( + _class.reference, r"voidCallback", r"(Ljava/lang/String;)V"); + + /// from: public abstract void voidCallback(java.lang.String s) + void voidCallback( + jni.JString s, + ) { + return jni.Jni.accessors.callMethodWithArgs(reference, _id_voidCallback, + jni.JniCallType.voidType, [s.reference]).check(); + } + + static final _id_stringCallback = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"stringCallback", + r"(Ljava/lang/String;)Ljava/lang/String;"); + + /// from: public abstract java.lang.String stringCallback(java.lang.String s) + /// The returned object must be released after use, by calling the [release] method. + jni.JString stringCallback( + jni.JString s, + ) { + return const jni.JStringType().fromRef(jni.Jni.accessors.callMethodWithArgs( + reference, + _id_stringCallback, + jni.JniCallType.objectType, + [s.reference]).object); + } + + static final _id_varCallback = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"varCallback", + r"(Ljava/lang/Object;)Ljava/lang/Object;"); + + /// from: public abstract T varCallback(T t) + /// The returned object must be released after use, by calling the [release] method. + $T varCallback( + $T t, + ) { + return T.fromRef(jni.Jni.accessors.callMethodWithArgs(reference, + _id_varCallback, jni.JniCallType.objectType, [t.reference]).object); + } + + static final _id_manyPrimitives = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"manyPrimitives", r"(IZCD)J"); + + /// from: public abstract long manyPrimitives(int a, boolean b, char c, double d) + int manyPrimitives( + int a, + bool b, + int c, + double d, + ) { + return jni.Jni.accessors.callMethodWithArgs( + reference, + _id_manyPrimitives, + jni.JniCallType.longType, + [jni.JValueInt(a), b ? 1 : 0, jni.JValueChar(c), d]).long; + } + + /// Maps a specific port to the implemented interface. + static final Map _$impls = {}; + ReceivePort? _$p; + + static jni.JObjectPtr _$invoke( + int port, + jni.JObjectPtr descriptor, + jni.JObjectPtr args, + ) { + return _$invokeMethod( + port, + $MethodInvocation.fromAddresses( + 0, + descriptor.address, + args.address, + ), + ); + } + + static final ffi.Pointer< + ffi.NativeFunction< + jni.JObjectPtr Function( + ffi.Uint64, jni.JObjectPtr, jni.JObjectPtr)>> + _$invokePointer = ffi.Pointer.fromFunction(_$invoke); + + static ffi.Pointer _$invokeMethod( + int $p, + $MethodInvocation $i, + ) { + try { + final $d = $i.methodDescriptor.toDartString(releaseOriginal: true); + final $a = $i.args; + if ($d == r"voidCallback(Ljava/lang/String;)V") { + _$impls[$p]!.voidCallback( + $a[0].castTo(const jni.JStringType(), releaseOriginal: true), + ); + return jni.nullptr; + } + if ($d == r"stringCallback(Ljava/lang/String;)Ljava/lang/String;") { + final $r = _$impls[$p]!.stringCallback( + $a[0].castTo(const jni.JStringType(), releaseOriginal: true), + ); + return ($r as jni.JObject).castTo(const jni.JObjectType()).toPointer(); + } + if ($d == r"varCallback(Ljava/lang/Object;)Ljava/lang/Object;") { + final $r = _$impls[$p]!.varCallback( + $a[0].castTo(_$impls[$p]!.T, releaseOriginal: true), + ); + return ($r as jni.JObject).castTo(const jni.JObjectType()).toPointer(); + } + if ($d == r"manyPrimitives(IZCD)J") { + final $r = _$impls[$p]!.manyPrimitives( + $a[0] + .castTo(const jni.JIntegerType(), releaseOriginal: true) + .intValue(releaseOriginal: true), + $a[1] + .castTo(const jni.JBooleanType(), releaseOriginal: true) + .booleanValue(releaseOriginal: true), + $a[2] + .castTo(const jni.JCharacterType(), releaseOriginal: true) + .charValue(releaseOriginal: true), + $a[3] + .castTo(const jni.JDoubleType(), releaseOriginal: true) + .doubleValue(releaseOriginal: true), + ); + return jni.JLong($r).toPointer(); + } + } catch (e) { + return ProtectedJniExtensions.newDartException(e.toString()); + } + return jni.nullptr; + } + + factory MyInterface.implement( + $MyInterfaceImpl<$T> $impl, + ) { + final $p = ReceivePort(); + final $x = MyInterface.fromRef( + $impl.T, + ProtectedJniExtensions.newPortProxy( + r"com.github.dart_lang.jnigen.interfaces.MyInterface", + $p, + _$invokePointer, + ), + ).._$p = $p; + final $a = $p.sendPort.nativePort; + _$impls[$a] = $impl; + $p.listen(($m) { + if ($m == null) { + _$impls.remove($p.sendPort.nativePort); + $p.close(); + return; + } + final $i = $MethodInvocation.fromMessage($m as List); + final $r = _$invokeMethod($p.sendPort.nativePort, $i); + ProtectedJniExtensions.returnResult($i.result, $r); + }); + return $x; + } + static Map get $impls => _$impls; +} + +abstract interface class $MyInterfaceImpl<$T extends jni.JObject> { + factory $MyInterfaceImpl({ + required jni.JObjType<$T> T, + required void Function(jni.JString s) voidCallback, + required jni.JString Function(jni.JString s) stringCallback, + required $T Function($T t) varCallback, + required int Function(int a, bool b, int c, double d) manyPrimitives, + }) = _$MyInterfaceImpl; + + jni.JObjType<$T> get T; + + void voidCallback(jni.JString s); + jni.JString stringCallback(jni.JString s); + $T varCallback($T t); + int manyPrimitives(int a, bool b, int c, double d); +} + +class _$MyInterfaceImpl<$T extends jni.JObject> + implements $MyInterfaceImpl<$T> { + _$MyInterfaceImpl({ + required this.T, + required void Function(jni.JString s) voidCallback, + required jni.JString Function(jni.JString s) stringCallback, + required $T Function($T t) varCallback, + required int Function(int a, bool b, int c, double d) manyPrimitives, + }) : _voidCallback = voidCallback, + _stringCallback = stringCallback, + _varCallback = varCallback, + _manyPrimitives = manyPrimitives; + + @override + final jni.JObjType<$T> T; + + final void Function(jni.JString s) _voidCallback; + final jni.JString Function(jni.JString s) _stringCallback; + final $T Function($T t) _varCallback; + final int Function(int a, bool b, int c, double d) _manyPrimitives; + + void voidCallback(jni.JString s) { + return _voidCallback(s); + } + + jni.JString stringCallback(jni.JString s) { + return _stringCallback(s); + } + + $T varCallback($T t) { + return _varCallback(t); + } + + int manyPrimitives(int a, bool b, int c, double d) { + return _manyPrimitives(a, b, c, d); + } +} + +final class $MyInterfaceType<$T extends jni.JObject> + extends jni.JObjType> { + final jni.JObjType<$T> T; + + const $MyInterfaceType( + this.T, + ); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/interfaces/MyInterface;"; + + @override + MyInterface<$T> fromRef(jni.JObjectPtr ref) => MyInterface.fromRef(T, ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => Object.hash($MyInterfaceType, T); + + @override + bool operator ==(Object other) { + return other.runtimeType == ($MyInterfaceType<$T>) && + other is $MyInterfaceType<$T> && + T == other.T; + } +} + +/// from: com.github.dart_lang.jnigen.interfaces.MyInterfaceConsumer +class MyInterfaceConsumer extends jni.JObject { + @override + late final jni.JObjType $type = type; + + MyInterfaceConsumer.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = jni.Jni.findJClass( + r"com/github/dart_lang/jnigen/interfaces/MyInterfaceConsumer"); + + /// The type which includes information such as the signature of this class. + static const type = $MyInterfaceConsumerType(); + static final _id_new0 = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"", r"()V"); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory MyInterfaceConsumer() { + return MyInterfaceConsumer.fromRef(jni.Jni.accessors + .newObjectWithArgs(_class.reference, _id_new0, []).object); + } + + static final _id_consumeOnAnotherThread = jni.Jni.accessors.getStaticMethodIDOf( + _class.reference, + r"consumeOnAnotherThread", + r"(Lcom/github/dart_lang/jnigen/interfaces/MyInterface;Ljava/lang/String;IZCDLjava/lang/Object;)V"); + + /// from: static public void consumeOnAnotherThread(com.github.dart_lang.jnigen.interfaces.MyInterface myInterface, java.lang.String s, int a, boolean b, char c, double d, T t) + static void consumeOnAnotherThread<$T extends jni.JObject>( + MyInterface<$T> myInterface, + jni.JString s, + int a, + bool b, + int c, + double d, + $T t, { + jni.JObjType<$T>? T, + }) { + T ??= jni.lowestCommonSuperType([ + t.$type, + (myInterface.$type as $MyInterfaceType).T, + ]) as jni.JObjType<$T>; + return jni.Jni.accessors.callStaticMethodWithArgs(_class.reference, + _id_consumeOnAnotherThread, jni.JniCallType.voidType, [ + myInterface.reference, + s.reference, + jni.JValueInt(a), + b ? 1 : 0, + jni.JValueChar(c), + d, + t.reference + ]).check(); + } + + static final _id_consumeOnSameThread = jni.Jni.accessors.getStaticMethodIDOf( + _class.reference, + r"consumeOnSameThread", + r"(Lcom/github/dart_lang/jnigen/interfaces/MyInterface;Ljava/lang/String;IZCDLjava/lang/Object;)V"); + + /// from: static public void consumeOnSameThread(com.github.dart_lang.jnigen.interfaces.MyInterface myInterface, java.lang.String s, int a, boolean b, char c, double d, T t) + static void consumeOnSameThread<$T extends jni.JObject>( + MyInterface<$T> myInterface, + jni.JString s, + int a, + bool b, + int c, + double d, + $T t, { + jni.JObjType<$T>? T, + }) { + T ??= jni.lowestCommonSuperType([ + t.$type, + (myInterface.$type as $MyInterfaceType).T, + ]) as jni.JObjType<$T>; + return jni.Jni.accessors.callStaticMethodWithArgs( + _class.reference, _id_consumeOnSameThread, jni.JniCallType.voidType, [ + myInterface.reference, + s.reference, + jni.JValueInt(a), + b ? 1 : 0, + jni.JValueChar(c), + d, + t.reference + ]).check(); + } +} + +final class $MyInterfaceConsumerType extends jni.JObjType { + const $MyInterfaceConsumerType(); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/interfaces/MyInterfaceConsumer;"; + + @override + MyInterfaceConsumer fromRef(jni.JObjectPtr ref) => + MyInterfaceConsumer.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($MyInterfaceConsumerType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($MyInterfaceConsumerType) && + other is $MyInterfaceConsumerType; + } +} + +/// from: com.github.dart_lang.jnigen.interfaces.MyRunnable +class MyRunnable extends jni.JObject { + @override + late final jni.JObjType $type = type; + + MyRunnable.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = + jni.Jni.findJClass(r"com/github/dart_lang/jnigen/interfaces/MyRunnable"); + + /// The type which includes information such as the signature of this class. + static const type = $MyRunnableType(); + static final _id_run = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"run", r"()V"); + + /// from: public abstract void run() + void run() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_run, jni.JniCallType.voidType, []).check(); + } + + /// Maps a specific port to the implemented interface. + static final Map _$impls = {}; + ReceivePort? _$p; + + static jni.JObjectPtr _$invoke( + int port, + jni.JObjectPtr descriptor, + jni.JObjectPtr args, + ) { + return _$invokeMethod( + port, + $MethodInvocation.fromAddresses( + 0, + descriptor.address, + args.address, + ), + ); + } + + static final ffi.Pointer< + ffi.NativeFunction< + jni.JObjectPtr Function( + ffi.Uint64, jni.JObjectPtr, jni.JObjectPtr)>> + _$invokePointer = ffi.Pointer.fromFunction(_$invoke); + + static ffi.Pointer _$invokeMethod( + int $p, + $MethodInvocation $i, + ) { + try { + final $d = $i.methodDescriptor.toDartString(releaseOriginal: true); + final $a = $i.args; + if ($d == r"run()V") { + _$impls[$p]!.run(); + return jni.nullptr; + } + } catch (e) { + return ProtectedJniExtensions.newDartException(e.toString()); + } + return jni.nullptr; + } + + factory MyRunnable.implement( + $MyRunnableImpl $impl, + ) { + final $p = ReceivePort(); + final $x = MyRunnable.fromRef( + ProtectedJniExtensions.newPortProxy( + r"com.github.dart_lang.jnigen.interfaces.MyRunnable", + $p, + _$invokePointer, + ), + ).._$p = $p; + final $a = $p.sendPort.nativePort; + _$impls[$a] = $impl; + $p.listen(($m) { + if ($m == null) { + _$impls.remove($p.sendPort.nativePort); + $p.close(); + return; + } + final $i = $MethodInvocation.fromMessage($m as List); + final $r = _$invokeMethod($p.sendPort.nativePort, $i); + ProtectedJniExtensions.returnResult($i.result, $r); + }); + return $x; + } +} + +abstract interface class $MyRunnableImpl { + factory $MyRunnableImpl({ + required void Function() run, + }) = _$MyRunnableImpl; + + void run(); +} + +class _$MyRunnableImpl implements $MyRunnableImpl { + _$MyRunnableImpl({ + required void Function() run, + }) : _run = run; + + final void Function() _run; + + void run() { + return _run(); + } +} + +final class $MyRunnableType extends jni.JObjType { + const $MyRunnableType(); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/interfaces/MyRunnable;"; + + @override + MyRunnable fromRef(jni.JObjectPtr ref) => MyRunnable.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($MyRunnableType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($MyRunnableType) && other is $MyRunnableType; + } +} + +/// from: com.github.dart_lang.jnigen.interfaces.MyRunnableRunner +class MyRunnableRunner extends jni.JObject { + @override + late final jni.JObjType $type = type; + + MyRunnableRunner.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = jni.Jni.findJClass( + r"com/github/dart_lang/jnigen/interfaces/MyRunnableRunner"); + + /// The type which includes information such as the signature of this class. + static const type = $MyRunnableRunnerType(); + static final _id_error = jni.Jni.accessors.getFieldIDOf( + _class.reference, + r"error", + r"Ljava/lang/Throwable;", + ); + + /// from: public java.lang.Throwable error + /// The returned object must be released after use, by calling the [release] method. + jni.JObject get error => const jni.JObjectType().fromRef(jni.Jni.accessors + .getField(reference, _id_error, jni.JniCallType.objectType) + .object); + + /// from: public java.lang.Throwable error + /// The returned object must be released after use, by calling the [release] method. + set error(jni.JObject value) => + jni.Jni.env.SetObjectField(reference, _id_error, value.reference); + + static final _id_new0 = jni.Jni.accessors.getMethodIDOf(_class.reference, + r"", r"(Lcom/github/dart_lang/jnigen/interfaces/MyRunnable;)V"); + + /// from: public void (com.github.dart_lang.jnigen.interfaces.MyRunnable runnable) + /// The returned object must be released after use, by calling the [release] method. + factory MyRunnableRunner( + MyRunnable runnable, + ) { + return MyRunnableRunner.fromRef(jni.Jni.accessors.newObjectWithArgs( + _class.reference, _id_new0, [runnable.reference]).object); + } + + static final _id_runOnSameThread = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"runOnSameThread", r"()V"); + + /// from: public void runOnSameThread() + void runOnSameThread() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_runOnSameThread, jni.JniCallType.voidType, []).check(); + } + + static final _id_runOnAnotherThread = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"runOnAnotherThread", r"()V"); + + /// from: public void runOnAnotherThread() + void runOnAnotherThread() { + return jni.Jni.accessors.callMethodWithArgs(reference, + _id_runOnAnotherThread, jni.JniCallType.voidType, []).check(); + } +} + +final class $MyRunnableRunnerType extends jni.JObjType { + const $MyRunnableRunnerType(); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/interfaces/MyRunnableRunner;"; + + @override + MyRunnableRunner fromRef(jni.JObjectPtr ref) => MyRunnableRunner.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($MyRunnableRunnerType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($MyRunnableRunnerType) && + other is $MyRunnableRunnerType; + } +} + +/// from: com.github.dart_lang.jnigen.annotations.JsonSerializable$Case +class JsonSerializable_Case extends jni.JObject { + @override + late final jni.JObjType $type = type; + + JsonSerializable_Case.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = jni.Jni.findJClass( + r"com/github/dart_lang/jnigen/annotations/JsonSerializable$Case"); + + /// The type which includes information such as the signature of this class. + static const type = $JsonSerializable_CaseType(); + static final _id_values = jni.Jni.accessors.getStaticMethodIDOf( + _class.reference, + r"values", + r"()[Lcom/github/dart_lang/jnigen/annotations/JsonSerializable$Case;"); + + /// from: static public com.github.dart_lang.jnigen.annotations.JsonSerializable.Case[] values() + /// The returned object must be released after use, by calling the [release] method. + static jni.JArray values() { + return const jni.JArrayType($JsonSerializable_CaseType()).fromRef( + jni.Jni.accessors.callStaticMethodWithArgs(_class.reference, _id_values, + jni.JniCallType.objectType, []).object); + } + + static final _id_valueOf = jni.Jni.accessors.getStaticMethodIDOf( + _class.reference, + r"valueOf", + r"(Ljava/lang/String;)Lcom/github/dart_lang/jnigen/annotations/JsonSerializable$Case;"); + + /// from: static public com.github.dart_lang.jnigen.annotations.JsonSerializable.Case valueOf(java.lang.String name) + /// The returned object must be released after use, by calling the [release] method. + static JsonSerializable_Case valueOf( + jni.JString name, + ) { + return const $JsonSerializable_CaseType().fromRef(jni.Jni.accessors + .callStaticMethodWithArgs(_class.reference, _id_valueOf, + jni.JniCallType.objectType, [name.reference]).object); + } +} + +final class $JsonSerializable_CaseType + extends jni.JObjType { + const $JsonSerializable_CaseType(); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/annotations/JsonSerializable$Case;"; + + @override + JsonSerializable_Case fromRef(jni.JObjectPtr ref) => + JsonSerializable_Case.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($JsonSerializable_CaseType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($JsonSerializable_CaseType) && + other is $JsonSerializable_CaseType; + } +} + +/// from: com.github.dart_lang.jnigen.annotations.MyDataClass +class MyDataClass extends jni.JObject { + @override + late final jni.JObjType $type = type; + + MyDataClass.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = jni.Jni.findJClass( + r"com/github/dart_lang/jnigen/annotations/MyDataClass"); + + /// The type which includes information such as the signature of this class. + static const type = $MyDataClassType(); + static final _id_new0 = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"", r"()V"); + + /// from: public void () + /// The returned object must be released after use, by calling the [release] method. + factory MyDataClass() { + return MyDataClass.fromRef(jni.Jni.accessors + .newObjectWithArgs(_class.reference, _id_new0, []).object); + } +} + +final class $MyDataClassType extends jni.JObjType { + const $MyDataClassType(); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/annotations/MyDataClass;"; + + @override + MyDataClass fromRef(jni.JObjectPtr ref) => MyDataClass.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($MyDataClassType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($MyDataClassType) && other is $MyDataClassType; + } +} diff --git a/pkgs/jnigen/test/simple_package_test/generate.dart b/pkgs/jnigen/test/simple_package_test/generate.dart new file mode 100644 index 000000000..9f5988880 --- /dev/null +++ b/pkgs/jnigen/test/simple_package_test/generate.dart @@ -0,0 +1,94 @@ +// 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. + +import 'dart:io'; + +import 'package:jnigen/src/config/experiments.dart'; +import 'package:logging/logging.dart'; +import 'package:path/path.dart'; +import 'package:jnigen/jnigen.dart'; + +const testName = 'simple_package_test'; +final testRoot = join('test', testName); +final javaPath = join(testRoot, 'java'); + +const preamble = ''' +// 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. + +'''; + +var javaPrefix = join('com', 'github', 'dart_lang', 'jnigen'); + +var javaFiles = [ + join(javaPrefix, 'simple_package', 'Example.java'), + join(javaPrefix, 'pkg2', 'C2.java'), + join(javaPrefix, 'pkg2', 'Example.java'), + join(javaPrefix, 'generics', 'MyStack.java'), + join(javaPrefix, 'generics', 'MyMap.java'), + join(javaPrefix, 'generics', 'GrandParent.java'), + join(javaPrefix, 'generics', 'StringStack.java'), + join(javaPrefix, 'generics', 'StringValuedMap.java'), + join(javaPrefix, 'generics', 'StringKeyedMap.java'), + join(javaPrefix, 'interfaces', 'MyRunnable.java'), + join(javaPrefix, 'interfaces', 'MyRunnableRunner.java'), + join(javaPrefix, 'interfaces', 'MyInterface.java'), + join(javaPrefix, 'interfaces', 'MyInterfaceConsumer.java'), + join(javaPrefix, 'annotations', 'JsonSerializable.java'), + join(javaPrefix, 'annotations', 'MyDataClass.java'), +]; + +void compileJavaSources(String workingDir, List files) async { + final procRes = Process.runSync('javac', files, workingDirectory: workingDir); + if (procRes.exitCode != 0) { + throw "javac exited with ${procRes.exitCode}\n" + "${procRes.stderr}"; + } +} + +Config getConfig([BindingsType bindingsType = BindingsType.cBased]) { + compileJavaSources(javaPath, javaFiles); + final typeDir = bindingsType.getConfigString(); + final cWrapperDir = Uri.directory(join(testRoot, typeDir, "c_bindings")); + final dartWrappersRoot = Uri.directory( + join(testRoot, typeDir, "dart_bindings"), + ); + final config = Config( + sourcePath: [Uri.directory(javaPath)], + classPath: [Uri.directory(javaPath)], + classes: [ + 'com.github.dart_lang.jnigen.simple_package', + 'com.github.dart_lang.jnigen.pkg2', + 'com.github.dart_lang.jnigen.generics', + 'com.github.dart_lang.jnigen.interfaces', + 'com.github.dart_lang.jnigen.annotations', + ], + logLevel: Level.INFO, + customClassBody: { + 'com.github.dart_lang.jnigen.interfaces.MyInterface': r''' + static Map get $impls => _$impls; +''' + }, + outputConfig: OutputConfig( + bindingsType: bindingsType, + cConfig: CCodeOutputConfig( + path: cWrapperDir, + libraryName: 'simple_package', + ), + dartConfig: DartCodeOutputConfig( + path: dartWrappersRoot.resolve('simple_package.dart'), + structure: OutputStructure.singleFile, + ), + ), + preamble: preamble, + experiments: {Experiment.interfaceImplementation}, + ); + return config; +} + +void main() async { + await generateJniBindings(getConfig(BindingsType.cBased)); + await generateJniBindings(getConfig(BindingsType.dartOnly)); +} diff --git a/pkgs/jnigen/test/simple_package_test/generated_files_test.dart b/pkgs/jnigen/test/simple_package_test/generated_files_test.dart new file mode 100644 index 000000000..0f595d2ff --- /dev/null +++ b/pkgs/jnigen/test/simple_package_test/generated_files_test.dart @@ -0,0 +1,26 @@ +// 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. + +import 'package:jnigen/jnigen.dart'; +import 'package:test/test.dart'; + +import 'generate.dart'; +import '../test_util/test_util.dart'; + +void main() async { + await checkLocallyBuiltDependencies(); + + generateAndCompareBothModes( + 'Generate and compare bindings for simple_package java files', + getConfig(BindingsType.cBased), + getConfig(BindingsType.dartOnly), + ); + + test("Generate and analyze bindings for simple_package - pure dart", + () async { + await generateAndAnalyzeBindings( + getConfig(BindingsType.dartOnly), + ); + }); // test if generated file == expected file +} diff --git a/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/annotations/JsonSerializable.java b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/annotations/JsonSerializable.java new file mode 100644 index 000000000..af7071e48 --- /dev/null +++ b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/annotations/JsonSerializable.java @@ -0,0 +1,19 @@ +// 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.annotations; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.SOURCE) +@Target(ElementType.TYPE) +public @interface JsonSerializable { + public static enum Case { + SNAKE_CASE, + KEBAB_CASE, + CAMEL_CASE + } + + public Case value(); +} diff --git a/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/annotations/MyDataClass.java b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/annotations/MyDataClass.java new file mode 100644 index 000000000..ff71b69d6 --- /dev/null +++ b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/annotations/MyDataClass.java @@ -0,0 +1,8 @@ +// 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.annotations; + +@JsonSerializable(JsonSerializable.Case.CAMEL_CASE) +public class MyDataClass {} diff --git a/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/generics/GenericTypeParams.java b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/generics/GenericTypeParams.java new file mode 100644 index 000000000..2a41875c3 --- /dev/null +++ b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/generics/GenericTypeParams.java @@ -0,0 +1,9 @@ +// Copyright (c) 2023, 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.generics; + +public class GenericTypeParams> {} + +// TODO: Add more cases of generic parameters diff --git a/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/generics/GrandParent.java b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/generics/GrandParent.java new file mode 100644 index 000000000..b7034034b --- /dev/null +++ b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/generics/GrandParent.java @@ -0,0 +1,74 @@ +// 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.generics; + +public class GrandParent { + public T value; + + public GrandParent(T value) { + this.value = value; + } + + public Parent stringParent() { + return new Parent<>("Hello"); + } + + public Parent varParent(S nestedValue) { + return new Parent<>(nestedValue); + } + + public static StaticParent stringStaticParent() { + return new StaticParent<>("Hello"); + } + + public static StaticParent varStaticParent(S value) { + return new StaticParent<>(value); + } + + public StaticParent staticParentWithSameType() { + return new StaticParent<>(value); + } + + // This doesn't have access to T + public static class StaticParent { + public S value; + + public StaticParent(S value) { + this.value = value; + } + + public class Child { + public S parentValue; + public U value; + + public Child(S parentValue, U value) { + this.parentValue = parentValue; + this.value = value; + } + } + } + + public class Parent { + public T parentValue; + public S value; + + public Parent(S newValue) { + parentValue = GrandParent.this.value; + value = newValue; + } + + public class Child { + public T grandParentValue; + public S parentValue; + public U value; + + public Child(U newValue) { + this.grandParentValue = GrandParent.this.value; + this.parentValue = Parent.this.value; + this.value = newValue; + } + } + } +} diff --git a/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/generics/MyMap.java b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/generics/MyMap.java new file mode 100644 index 000000000..21392ae5f --- /dev/null +++ b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/generics/MyMap.java @@ -0,0 +1,42 @@ +// 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.generics; + +import java.util.HashMap; +import java.util.Map; + +public class MyMap { + public class MyEntry { + public K key; + public V value; + + public MyEntry(K key, V value) { + this.key = key; + this.value = value; + } + } + + private Map map; + + public MyMap() { + map = new HashMap<>(); + } + + public V get(K key) { + return map.get(key); + } + + public V put(K key, V value) { + return map.put(key, value); + } + + public MyStack entryStack() { + var stack = new MyStack(); + map.entrySet().stream() + .map(e -> new MyEntry(e.getKey(), e.getValue())) + .forEach(e -> stack.push(e)); + return stack; + } +} diff --git a/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/generics/MyStack.java b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/generics/MyStack.java new file mode 100644 index 000000000..c4e2d06f4 --- /dev/null +++ b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/generics/MyStack.java @@ -0,0 +1,59 @@ +// 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.generics; + +import java.util.Stack; + +public class MyStack { + private Stack stack; + + public MyStack() { + stack = new Stack<>(); + } + + public static MyStack fromArray(T[] arr) { + var stack = new MyStack(); + for (int i = 0; i < arr.length; ++i) { + stack.push(arr[i]); + } + return stack; + } + + public static MyStack fromArrayOfArrayOfGrandParents(GrandParent[][] arr) { + // just for testing + var stack = new MyStack(); + stack.push(arr[0][0].value); + return stack; + } + + public static MyStack of() { + return new MyStack(); + } + + public static MyStack of(T obj) { + var stack = new MyStack(); + stack.push(obj); + return stack; + } + + public static MyStack of(T obj, T obj2) { + var stack = new MyStack(); + stack.push(obj); + stack.push(obj2); + return stack; + } + + public void push(T item) { + stack.push(item); + } + + public T pop() { + return stack.pop(); + } + + public int size() { + return stack.size(); + } +} diff --git a/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/generics/StringKeyedMap.java b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/generics/StringKeyedMap.java new file mode 100644 index 000000000..1ca40aad4 --- /dev/null +++ b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/generics/StringKeyedMap.java @@ -0,0 +1,7 @@ +// 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.generics; + +public class StringKeyedMap extends MyMap {} diff --git a/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/generics/StringMap.java b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/generics/StringMap.java new file mode 100644 index 000000000..05f9365e4 --- /dev/null +++ b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/generics/StringMap.java @@ -0,0 +1,7 @@ +// Copyright (c) 2023, 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.generics; + +public class StringMap extends StringKeyedMap {} diff --git a/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/generics/StringStack.java b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/generics/StringStack.java new file mode 100644 index 000000000..87fd0412c --- /dev/null +++ b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/generics/StringStack.java @@ -0,0 +1,7 @@ +// 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.generics; + +public class StringStack extends MyStack {} diff --git a/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/generics/StringValuedMap.java b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/generics/StringValuedMap.java new file mode 100644 index 000000000..c005ae0d3 --- /dev/null +++ b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/generics/StringValuedMap.java @@ -0,0 +1,7 @@ +// 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.generics; + +public class StringValuedMap extends MyMap {} diff --git a/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/inheritance/BaseClass.java b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/inheritance/BaseClass.java new file mode 100644 index 000000000..f9157e426 --- /dev/null +++ b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/inheritance/BaseClass.java @@ -0,0 +1,7 @@ +// Copyright (c) 2023, 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.inheritance; + +public class BaseClass {} diff --git a/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/inheritance/GenericDerivedClass.java b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/inheritance/GenericDerivedClass.java new file mode 100644 index 000000000..5829657f7 --- /dev/null +++ b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/inheritance/GenericDerivedClass.java @@ -0,0 +1,7 @@ +// Copyright (c) 2023, 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.inheritance; + +public class GenericDerivedClass extends BaseClass {} diff --git a/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/inheritance/SpecificDerivedClass.java b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/inheritance/SpecificDerivedClass.java new file mode 100644 index 000000000..6c33e8315 --- /dev/null +++ b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/inheritance/SpecificDerivedClass.java @@ -0,0 +1,7 @@ +// Copyright (c) 2023, 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.inheritance; + +public class SpecificDerivedClass extends BaseClass {} diff --git a/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/interfaces/MyInterface.java b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/interfaces/MyInterface.java new file mode 100644 index 000000000..97b243e52 --- /dev/null +++ b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/interfaces/MyInterface.java @@ -0,0 +1,15 @@ +// Copyright (c) 2023, 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.interfaces; + +public interface MyInterface { + void voidCallback(String s); + + String stringCallback(String s); + + T varCallback(T t); + + long manyPrimitives(int a, boolean b, char c, double d); +} diff --git a/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/interfaces/MyInterfaceConsumer.java b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/interfaces/MyInterfaceConsumer.java new file mode 100644 index 000000000..b4eeb2fda --- /dev/null +++ b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/interfaces/MyInterfaceConsumer.java @@ -0,0 +1,21 @@ +// Copyright (c) 2023, 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.interfaces; + +public class MyInterfaceConsumer { + public static void consumeOnAnotherThread( + MyInterface myInterface, String s, int a, boolean b, char c, double d, T t) { + var thread = new Thread(() -> consumeOnSameThread(myInterface, s, a, b, c, d, t)); + thread.start(); + } + + public static void consumeOnSameThread( + MyInterface myInterface, String s, int a, boolean b, char c, double d, T t) { + String result = myInterface.stringCallback(s); + myInterface.voidCallback(result); + myInterface.manyPrimitives(a, b, c, d); + myInterface.varCallback(t); + } +} diff --git a/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/interfaces/MyRunnable.java b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/interfaces/MyRunnable.java new file mode 100644 index 000000000..4a39f8154 --- /dev/null +++ b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/interfaces/MyRunnable.java @@ -0,0 +1,9 @@ +// Copyright (c) 2023, 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.interfaces; + +public interface MyRunnable { + void run(); +} diff --git a/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/interfaces/MyRunnableRunner.java b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/interfaces/MyRunnableRunner.java new file mode 100644 index 000000000..2903f37e0 --- /dev/null +++ b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/interfaces/MyRunnableRunner.java @@ -0,0 +1,28 @@ +// Copyright (c) 2023, 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.interfaces; + +public class MyRunnableRunner { + final MyRunnable runnable; + + public Throwable error; + + public MyRunnableRunner(MyRunnable runnable) { + this.runnable = runnable; + } + + public void runOnSameThread() { + try { + runnable.run(); + } catch (Throwable e) { + error = e; + } + } + + public void runOnAnotherThread() { + var thread = new Thread(this::runOnSameThread); + thread.start(); + } +} diff --git a/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/pkg2/C2.java b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/pkg2/C2.java new file mode 100644 index 000000000..fde1e6d6a --- /dev/null +++ b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/pkg2/C2.java @@ -0,0 +1,9 @@ +// 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.pkg2; + +public class C2 { + public static int CONSTANT = 12; +} diff --git a/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/pkg2/Example.java b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/pkg2/Example.java new file mode 100644 index 000000000..6cce45550 --- /dev/null +++ b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/pkg2/Example.java @@ -0,0 +1,13 @@ +// 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. + +/// This class is named the same as `Example` in other package to verify the renaming works. + +package com.github.dart_lang.jnigen.pkg2; + +public class Example { + public int whichExample() { + return 1; + } +} diff --git a/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/simple_package/Color.java b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/simple_package/Color.java new file mode 100644 index 000000000..efb96c6e4 --- /dev/null +++ b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/simple_package/Color.java @@ -0,0 +1,14 @@ +// Copyright (c) 2023, 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.simple_package; + +public enum Color { + RED, + BLUE, + BLACK, + GREEN, + YELLOW, + LIME +} diff --git a/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/simple_package/Example.java b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/simple_package/Example.java new file mode 100644 index 000000000..b96156eba --- /dev/null +++ b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/simple_package/Example.java @@ -0,0 +1,238 @@ +// 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.simple_package; + +import java.util.*; + +public class Example { + // static fields - primitive & string + public static final int ON = 1; + public static final int OFF = 0; + public static final double PI = 3.14159; + public static final char SEMICOLON = ';'; + public static final String SEMICOLON_STRING = ";"; + + public static final Random unusedRandom = new Random(); + + private static int amount = 500; + private static double pi = 3.14159; + private static char asterisk = '*'; + private static String name = "Ragnar Lothbrok"; + + // Static fields - object + private static Nested nested = new Nested(true); + + // static methods + public static int getAmount() { + return amount; + } + + public static double getPi() { + return pi; + } + + public static char getAsterisk() { + return asterisk; + } + + public static String getName() { + return name; + } + + public static Nested getNestedInstance() { + return nested; + } + + // void functions with 1 parameter + public static void setAmount(int newAmount) { + amount = newAmount; + } + + public static void setName(String newName) { + name = newName; + } + + public static void setNestedInstance(Nested newNested) { + nested = newNested; + } + + // void functions with many parameters + public static int max4(int a, int b, int c, int d) { + return Integer.max(Integer.max(a, b), Integer.max(c, d)); + } + + public static int max8(int a, int b, int c, int d, int e, int f, int g, int h) { + return Integer.max(max4(a, b, c, d), max4(e, f, g, h)); + } + + // Instance fields - primitive and string + private int number = 0; + private boolean isUp = false; + private String codename = "achilles"; + + // Instance fields - object + private Random random = new Random(); + + // Instance methods + public int getNumber() { + return number; + } + + public void setNumber(int number) { + this.number = number; + } + + public boolean getIsUp() { + return isUp; + } + + public void setUp(boolean isUp) { + this.isUp = isUp; + } + + public String getCodename() { + return codename; + } + + public void setCodename(String codename) { + this.codename = codename; + } + + public Random getRandom() { + return random; + } + + public void setRandom(Random random) { + this.random = random; + } + + public long getRandomLong() { + return random.nextLong(); + } + + public long add4Longs(long a, long b, long c, long d) { + return a + b + c + d; + } + + public long add8Longs(long a, long b, long c, long d, long e, long f, long g, long h) { + return a + b + c + d + e + f + g + h; + } + + public String getRandomNumericString(Random random) { + return String.format( + "%d%d%d%d", random.nextInt(10), random.nextInt(10), random.nextInt(10), random.nextInt(10)); + } + + private void privateMethod(String a, String b) {} + + protected void protectedMethod(String a, String b) {} + + protected Random protectedField; + + public final void finalMethod() {} + + public List getList() { + return null; + } + + /** Joins the strings in the list using the given delimiter. */ + public String joinStrings(List values, String delim) { + return null; + } + + public void methodWithSeveralParams( + char ch, String s, int[] a, T t, List lt, Map wm) {} + + public Example() { + this(0); + } + + public Example(int number) { + this(number, true); + } + + public Example(int number, boolean isUp) { + this(number, isUp, "achilles"); + } + + public Example(int number, boolean isUp, String codename) { + this.number = number; + this.isUp = isUp; + this.codename = codename; + } + + public Example(int a, int b, int c, int d, int e, int f, int g, int h) { + this(a + b + c + d + e + f + g + h); + } + + public int whichExample() { + return 0; + } + + public static int addInts(int a, int b) { + return a + b; + } + + public static int[] getArr() { + return new int[] {1, 2, 3}; + } + + public static int addAll(int[] arr) { + return Arrays.stream(arr).sum(); + } + + public Example getSelf() { + return this; + } + + public static void throwException() { + throw new RuntimeException("Hello"); + } + + public void overloaded() {} + + public void overloaded(int a, String b) {} + + public void overloaded(int a) {} + + public void overloaded(List a, String b) {} + + public void overloaded(List a) {} + + public class NonStaticNested { + public boolean ok; + } + + public static class Nested { + private boolean value; + + public Nested(boolean value) { + this.value = value; + } + + public void usesAnonymousInnerClass() { + new Thread( + new Runnable() { + @Override + public void run() { + System.out.println("2982157093127690243"); + } + }) + .start(); + } + + public boolean getValue() { + return value; + } + + public void setValue(boolean value) { + this.value = value; + } + + public static class NestedTwice { + public static int ZERO = 0; + } + } +} diff --git a/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/simple_package/Exceptions.java b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/simple_package/Exceptions.java new file mode 100644 index 000000000..e0e79b344 --- /dev/null +++ b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/simple_package/Exceptions.java @@ -0,0 +1,82 @@ +// Copyright (c) 2023, 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.simple_package; + +import java.io.*; +import java.util.*; + +public class Exceptions { + public Exceptions() {} + + // constructor throwing exception + public Exceptions(float x) { + throw new IllegalArgumentException("Float is not a serious type"); + } + + public Exceptions(int a, int b, int c, int d, int e, int f) { + throw new IllegalArgumentException("Too many arguments, but none in your favor"); + } + + public static Object staticObjectMethod() { + throw new RuntimeException(":-/"); + } + + public static int staticIntMethod() { + throw new RuntimeException("\\-:"); + } + + public static Object[] staticObjectArrayMethod() { + throw new RuntimeException(":-/[]"); + } + + public static int[] staticIntArrayMethod() { + throw new RuntimeException("\\-:[]"); + } + + public Object objectMethod() { + throw new RuntimeException("['--']"); + } + + public int intMethod() { + throw new RuntimeException("[-_-]"); + } + + public Object[] objectArrayMethod() { + throw new RuntimeException(":-/[]"); + } + + public int[] intArrayMethod() { + throw new RuntimeException("\\-:[]"); + } + + public int throwNullPointerException() { + Random random = null; + return random.nextInt(); + } + + public InputStream throwFileNotFoundException() throws IOException { + return new FileInputStream("/dev/nulll/59613/287"); + } + + public FileInputStream throwClassCastException() { + InputStream x = System.in; + return (FileInputStream) x; + } + + public int throwArrayIndexException() { + int[] nums = {1, 2}; + return nums[4]; + } + + public int throwArithmeticException() { + int x = 10; + int y = 100 - 100 + 1 - 1; + return x / y; + } + + public static void throwLoremIpsum() { + throw new RuntimeException("Lorem Ipsum"); + } +} diff --git a/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/simple_package/Fields.java b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/simple_package/Fields.java new file mode 100644 index 000000000..face69c17 --- /dev/null +++ b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/simple_package/Fields.java @@ -0,0 +1,34 @@ +// 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.simple_package; + +import java.util.*; + +public class Fields { + // static fields - non-final primitive & string + public static int amount = 500; + public static double pi = 3.14159; + public static char asterisk = '*'; + public static String name = "Earl Haraldson"; + + // Static fields - object + public Integer i = 100; + + // Instance fields - primitive and string + public long trillion = 1024L * 1024L * 1024L * 1024L; + public boolean isAchillesDead = false; + public String bestFighterInGreece = "Achilles"; + + // Instance fields - object + public Random random = new Random(); + + // Static and instance fields in nested class. + public static class Nested { + public long hundred = 100L; + public static String BEST_GOD = "Pallas Athena"; + } + + public static char euroSymbol = '\u20ac'; +} diff --git a/pkgs/jnigen/test/simple_package_test/runtime_test_registrant.dart b/pkgs/jnigen/test/simple_package_test/runtime_test_registrant.dart new file mode 100644 index 000000000..3791f9e45 --- /dev/null +++ b/pkgs/jnigen/test/simple_package_test/runtime_test_registrant.dart @@ -0,0 +1,741 @@ +// Copyright (c) 2023, 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. + +import 'dart:async'; +import 'dart:io'; + +import 'package:test/test.dart'; +import 'package:jni/jni.dart'; + +import '../test_util/callback_types.dart'; + +import 'c_based/dart_bindings/simple_package.dart'; + +const pi = 3.14159; +const fpDelta = 0.001; +const trillion = 1024 * 1024 * 1024 * 1024; + +void _runJavaGC() { + final managementFactory = + Jni.findJClass('java/lang/management/ManagementFactory'); + final bean = managementFactory.callStaticMethodByName( + 'getRuntimeMXBean', '()Ljava/lang/management/RuntimeMXBean;', []); + final pid = bean.callMethodByName('getPid', '()J', []); + ProcessResult result; + do { + result = Process.runSync('jcmd', [pid.toString(), 'GC.run']); + sleep(const Duration(milliseconds: 100)); + } while (result.exitCode != 0); +} + +void registerTests(String groupName, TestRunnerCallback test) { + group(groupName, () { + test('static final fields - int', () { + expect(Example.ON, equals(1)); + expect(Example.OFF, equals(0)); + expect(Example.PI, closeTo(pi, fpDelta)); + expect(Example.SEMICOLON, equals(';'.codeUnitAt(0))); + expect(Example.SEMICOLON_STRING, equals(';')); + }); + + test('Static methods - primitive', () { + // same test can be run at a replicated (dart-only) test, check for both + // possible values. + expect(Example.getAmount(), isIn([1012, 500])); + Example.setAmount(1012); + expect(Example.getAmount(), equals(1012)); + expect(Example.getAsterisk(), equals('*'.codeUnitAt(0))); + expect(C2.CONSTANT, equals(12)); + }); + + test('Static fields & methods - string', () { + expect( + Example.getName().toDartString(releaseOriginal: true), + isIn(["Ragnar Lothbrok", "Theseus"]), + ); + Example.setName("Theseus".toJString()); + expect( + Example.getName().toDartString(releaseOriginal: true), + equals("Theseus"), + ); + }); + + test('Static fields and methods - Object', () { + final nested = Example.getNestedInstance(); + expect(nested.getValue(), isIn([true, false])); + nested.setValue(false); + expect(nested.getValue(), isFalse); + }); + + test('static methods with several arguments', () { + expect(Example.addInts(10, 15), equals(25)); + expect(Example.max4(-1, 15, 30, 12), equals(30)); + expect(Example.max8(1, 4, 8, 2, 4, 10, 8, 6), equals(10)); + }); + + test('Instance methods (getters & setters)', () { + final e = Example(); + expect(e.getNumber(), equals(0)); + expect(e.getIsUp(), true); + expect(e.getCodename().toDartString(), equals("achilles")); + e.setNumber(1); + e.setUp(false); + e.setCodename("spartan".toJString()); + expect(e.getIsUp(), false); + expect(e.getNumber(), 1); + expect(e.getCodename().toDartString(), equals("spartan")); + e.release(); + }); + + test('Instance methods with several arguments', () { + final e = Example(); + expect(e.add4Longs(1, 2, 3, 4), equals(10)); + expect(e.add8Longs(1, 1, 2, 2, 3, 3, 12, 24), equals(48)); + expect( + e.add4Longs(trillion, trillion, trillion, trillion), + equals(4 * trillion), + ); + expect( + e.add8Longs(trillion, -trillion, trillion, -trillion, trillion, + -trillion, -trillion, -trillion), + equals(2 * -trillion), + ); + e.release(); + }); + + test('Misc. instance methods', () { + final e = Example(); + final rand = e.getRandom(); + expect(rand.isNull, isFalse); + final _ = e.getRandomLong(); + final id = + e.getRandomNumericString(rand).toDartString(releaseOriginal: true); + expect(int.parse(id), lessThan(10000)); + e.setNumber(145); + expect( + e.getSelf().getSelf().getSelf().getSelf().getNumber(), + equals(145), + ); + e.release(); + }); + + test('Constructors', () { + final e0 = Example(); + expect(e0.getNumber(), 0); + expect(e0.getIsUp(), true); + expect(e0.getCodename().toDartString(), equals('achilles')); + final e1 = Example.new1(111); + expect(e1.getNumber(), equals(111)); + expect(e1.getIsUp(), true); + expect(e1.getCodename().toDartString(), "achilles"); + final e2 = Example.new2(122, false); + expect(e2.getNumber(), equals(122)); + expect(e2.getIsUp(), false); + expect(e2.getCodename().toDartString(), "achilles"); + final e3 = Example.new3(133, false, "spartan".toJString()); + expect(e3.getNumber(), equals(133)); + expect(e3.getIsUp(), false); + expect(e3.getCodename().toDartString(), "spartan"); + }); + + test('Static (non-final) fields', () { + // Other replica test may already have modified this, so assert both + // values. + expect(Fields.amount, isIn([500, 101])); + Fields.amount = 101; + expect(Fields.amount, equals(101)); + + expect(Fields.asterisk, equals('*'.codeUnitAt(0))); + + expect( + Fields.name.toDartString(), + isIn(["Earl Haraldson", "Ragnar Lothbrok"]), + ); + + Fields.name = "Ragnar Lothbrok".toJString(); + expect(Fields.name.toDartString(), equals("Ragnar Lothbrok")); + + expect(Fields.pi, closeTo(pi, fpDelta)); + }); + + test('Instance fields', () { + final f = Fields(); + expect(f.trillion, equals(trillion)); + + expect(f.isAchillesDead, isFalse); + expect(f.bestFighterInGreece.toDartString(), equals("Achilles")); + // "For your glory walks hand-in-hand with your doom." - Thetis. + f.isAchillesDead = true; + // I don't know much Greek mythology. But Troy was released in 2004, + // and 300 was released in 2006, so it's Leonidas I. + f.bestFighterInGreece = "Leonidas I".toJString(); + expect(f.isAchillesDead, isTrue); + expect(f.bestFighterInGreece.toDartString(), "Leonidas I"); + }); + + test('Fields from nested class', () { + expect(Fields_Nested().hundred, equals(100)); + // Hector of Troy may disagree. + expect(Fields_Nested.BEST_GOD.toDartString(), equals('Pallas Athena')); + }); + + test('static methods arrays', () { + final array = Example.getArr(); + expect(array[0], 1); + expect(array[1], 2); + expect(array[2], 3); + expect(Example.addAll(array), 6); + array[0] = 4; + expect(Example.addAll(array), 9); + }); + + test('array of the class', () { + final ex1 = Example(); + final ex2 = Example(); + ex1.setNumber(1); + ex2.setNumber(2); + final array = JArray(Example.type, 2); + array[0] = ex1; + array[1] = ex2; + expect(array[0].getNumber(), 1); + expect(array[1].getNumber(), 2); + array.release(); + ex1.release(); + ex2.release(); + }); + + test("Check bindings for same-named classes", () { + expect(Example().whichExample(), 0); + expect(Example1().whichExample(), 1); + }); + + test('Unicode char', () { + expect(Fields.euroSymbol, equals('\u20AC'.codeUnitAt(0))); + }); + + group('exception tests', () { + void throwsException(void Function() f) { + expect(f, throwsA(isA())); + } + + test('Example throw exception', () { + throwsException(Example.throwException); + }); + + test('Exception from method returning Object', () { + throwsException(Exceptions.staticObjectMethod); + throwsException(Exceptions.staticObjectArrayMethod); + final x = Exceptions(); + throwsException(x.objectMethod); + throwsException(x.objectArrayMethod); + }); + + test('Exception from method returning int', () { + throwsException(Exceptions.staticIntMethod); + throwsException(Exceptions.staticIntArrayMethod); + final x = Exceptions(); + throwsException(x.intMethod); + throwsException(x.intArrayMethod); + }); + + test('Exception from constructor', () { + throwsException(() => Exceptions.new1(6.8)); + throwsException(() => Exceptions.new2(1, 2, 3, 4, 5, 6)); + }); + + test('Exception contains error message & stack trace', () { + try { + Exceptions.throwLoremIpsum(); + } on JniException catch (e) { + expect(e.message, stringContainsInOrder(["Lorem Ipsum"])); + expect( + e.toString(), + stringContainsInOrder(["Lorem Ipsum", "throwLoremIpsum"]), + ); + return; + } + throw AssertionError("No exception was thrown"); + }); + }); + + group('generics', () { + test('GrandParent constructor', () { + using((arena) { + final grandParent = + GrandParent('Hello'.toJString()..releasedBy(arena)) + ..releasedBy(arena); + expect(grandParent, isA>()); + expect(grandParent.$type, isA<$GrandParentType>()); + expect( + grandParent.value.toDartString(releaseOriginal: true), 'Hello'); + }); + }); + test('MyStack', () { + using((arena) { + final stack = MyStack(T: JString.type)..releasedBy(arena); + stack.push('Hello'.toJString()..releasedBy(arena)); + stack.push('World'.toJString()..releasedBy(arena)); + expect(stack.pop().toDartString(releaseOriginal: true), 'World'); + expect(stack.pop().toDartString(releaseOriginal: true), 'Hello'); + }); + }); + test('Different stacks have different types, same stacks have same types', + () { + using((arena) { + final aStringStack = MyStack(T: JString.type)..releasedBy(arena); + final anotherStringStack = MyStack(T: JString.type) + ..releasedBy(arena); + final anObjectStack = MyStack(T: JObject.type)..releasedBy(arena); + expect(aStringStack.$type, anotherStringStack.$type); + expect( + aStringStack.$type.hashCode, + anotherStringStack.$type.hashCode, + ); + expect(aStringStack.$type, isNot(anObjectStack.$type)); + expect( + aStringStack.$type.hashCode, + isNot(anObjectStack.$type.hashCode), + ); + }); + }); + test('MyMap', () { + using((arena) { + final map = MyMap(K: JString.type, V: Example.type) + ..releasedBy(arena); + final helloExample = Example.new1(1)..releasedBy(arena); + final worldExample = Example.new1(2)..releasedBy(arena); + map.put('Hello'.toJString()..releasedBy(arena), helloExample); + map.put('World'.toJString()..releasedBy(arena), worldExample); + expect( + (map.get0('Hello'.toJString()..releasedBy(arena)) + ..releasedBy(arena)) + .getNumber(), + 1, + ); + expect( + (map.get0('World'.toJString()..releasedBy(arena)) + ..releasedBy(arena)) + .getNumber(), + 2, + ); + expect( + ((map.entryStack()..releasedBy(arena)).pop()..releasedBy(arena)) + .key + .castTo(JString.type, releaseOriginal: true) + .toDartString(releaseOriginal: true), + anyOf('Hello', 'World'), + ); + }); + }); + group('classes extending generics', () { + test('StringStack', () { + using((arena) { + final stringStack = StringStack()..releasedBy(arena); + stringStack.push('Hello'.toJString()..releasedBy(arena)); + expect( + stringStack.pop().toDartString(releaseOriginal: true), 'Hello'); + }); + }); + test('StringKeyedMap', () { + using((arena) { + final map = StringKeyedMap(V: Example.type)..releasedBy(arena); + final example = Example()..releasedBy(arena); + map.put('Hello'.toJString()..releasedBy(arena), example); + expect( + (map.get0('Hello'.toJString()..releasedBy(arena)) + ..releasedBy(arena)) + .getNumber(), + 0, + ); + }); + }); + test('StringValuedMap', () { + using((arena) { + final map = StringValuedMap(K: Example.type)..releasedBy(arena); + final example = Example()..releasedBy(arena); + map.put(example, 'Hello'.toJString()..releasedBy(arena)); + expect( + map.get0(example).toDartString(releaseOriginal: true), + 'Hello', + ); + }); + }); + test('StringMap', () { + using((arena) { + final map = StringMap()..releasedBy(arena); + map.put('hello'.toJString()..releasedBy(arena), + 'world'.toJString()..releasedBy(arena)); + expect( + map + .get0('hello'.toJString()..releasedBy(arena)) + .toDartString(releaseOriginal: true), + 'world', + ); + }); + }); + }); + test('superclass count', () { + expect(JObject.type.superCount, 0); + expect(MyMap.type(JObject.type, JObject.type).superCount, 1); + expect(StringKeyedMap.type(JObject.type).superCount, 2); + expect(StringValuedMap.type(JObject.type).superCount, 2); + expect(StringMap.type.superCount, 3); + }); + test('nested generics', () { + using((arena) { + final grandParent = + GrandParent(T: JString.type, "!".toJString()..releasedBy(arena)) + ..releasedBy(arena); + expect( + grandParent.value.toDartString(releaseOriginal: true), + "!", + ); + + final strStaticParent = GrandParent.stringStaticParent() + ..releasedBy(arena); + expect( + strStaticParent.value.toDartString(releaseOriginal: true), + "Hello", + ); + + final exampleStaticParent = GrandParent.varStaticParent( + S: Example.type, Example()..releasedBy(arena)) + ..releasedBy(arena); + expect( + (exampleStaticParent.value..releasedBy(arena)).getNumber(), + 0, + ); + + final strParent = grandParent.stringParent()..releasedBy(arena); + expect( + strParent.parentValue + .castTo(JString.type, releaseOriginal: true) + .toDartString(releaseOriginal: true), + "!", + ); + expect( + strParent.value.toDartString(releaseOriginal: true), + "Hello", + ); + + final exampleParent = grandParent.varParent( + S: Example.type, Example()..releasedBy(arena)) + ..releasedBy(arena); + expect( + exampleParent.parentValue + .castTo(JString.type, releaseOriginal: true) + .toDartString(releaseOriginal: true), + "!", + ); + expect( + (exampleParent.value..releasedBy(arena)).getNumber(), + 0, + ); + // TODO(#139): test constructing Child, currently does not work due + // to a problem with C-bindings. + }); + }); + }); + test('Constructing non-static nested classes', () { + using((arena) { + final grandParent = GrandParent(1.toJInteger())..releasedBy(arena); + final parent = GrandParent_Parent(grandParent, 2.toJInteger()) + ..releasedBy(arena); + final child = GrandParent_Parent_Child(parent, 3.toJInteger()) + ..releasedBy(arena); + expect(grandParent.value.intValue(releaseOriginal: true), 1); + expect(parent.parentValue.intValue(releaseOriginal: true), 1); + expect(parent.value.intValue(releaseOriginal: true), 2); + expect(child.grandParentValue.intValue(releaseOriginal: true), 1); + expect(child.parentValue.intValue(releaseOriginal: true), 2); + expect(child.value.intValue(releaseOriginal: true), 3); + }); + }); + + group('Generic type inference', () { + test('MyStack.of1', () { + using((arena) { + final emptyStack = MyStack(T: JString.type)..releasedBy(arena); + expect(emptyStack.size(), 0); + final stack = MyStack.of1( + "Hello".toJString()..releasedBy(arena), + )..releasedBy(arena); + expect(stack, isA>()); + expect(stack.$type, isA<$MyStackType>()); + expect( + stack.pop().toDartString(releaseOriginal: true), + "Hello", + ); + }); + }); + test('MyStack.of 2 strings', () { + using((arena) { + final stack = MyStack.of2( + "Hello".toJString()..releasedBy(arena), + "World".toJString()..releasedBy(arena), + )..releasedBy(arena); + expect(stack, isA>()); + expect(stack.$type, isA<$MyStackType>()); + expect( + stack.pop().toDartString(releaseOriginal: true), + "World", + ); + expect( + stack.pop().toDartString(releaseOriginal: true), + "Hello", + ); + }); + }); + test('MyStack.of a string and an array', () { + using((arena) { + final array = JArray.filled(1, "World".toJString()..releasedBy(arena)) + ..releasedBy(arena); + final stack = MyStack.of2( + "Hello".toJString()..releasedBy(arena), + array, + )..releasedBy(arena); + expect(stack, isA>()); + expect(stack.$type, isA<$MyStackType>()); + expect( + stack + .pop() + .castTo(JArray.type(JString.type), releaseOriginal: true)[0] + .toDartString(releaseOriginal: true), + "World", + ); + expect( + stack + .pop() + .castTo(JString.type, releaseOriginal: true) + .toDartString(releaseOriginal: true), + "Hello", + ); + }); + }); + test('MyStack.from array of string', () { + using((arena) { + final array = JArray.filled(1, "Hello".toJString()..releasedBy(arena)) + ..releasedBy(arena); + final stack = MyStack.fromArray(array)..releasedBy(arena); + expect(stack, isA>()); + expect(stack.$type, isA<$MyStackType>()); + expect( + stack.pop().toDartString(releaseOriginal: true), + "Hello", + ); + }); + }); + test('MyStack.fromArrayOfArrayOfGrandParents', () { + using((arena) { + final firstDimention = JArray.filled( + 1, + GrandParent("Hello".toJString()..releasedBy(arena)) + ..releasedBy(arena), + )..releasedBy(arena); + final twoDimentionalArray = JArray.filled(1, firstDimention) + ..releasedBy(arena); + final stack = + MyStack.fromArrayOfArrayOfGrandParents(twoDimentionalArray) + ..releasedBy(arena); + expect(stack, isA>()); + expect(stack.$type, isA<$MyStackType>()); + expect( + stack.pop().toDartString(releaseOriginal: true), + "Hello", + ); + }); + }); + }); + }); + + group('interface implementation', () { + for (final (threading, consume) in [ + ('another thread', MyInterfaceConsumer.consumeOnAnotherThread), + ('the same thread', MyInterfaceConsumer.consumeOnSameThread), + ]) { + test('MyInterface.implement on $threading', () async { + final voidCallbackResult = Completer(); + final varCallbackResult = Completer(); + final manyPrimitivesResult = Completer(); + // We can use this trick to access self, instead of generating a `thiz` + // or `self` argument for each one of the callbacks. + late final MyInterface myInterface; + myInterface = MyInterface.implement( + $MyInterfaceImpl( + voidCallback: (s) { + voidCallbackResult.complete(s); + }, + stringCallback: (s) { + return (s.toDartString(releaseOriginal: true) * 2).toJString(); + }, + varCallback: (JInteger t) { + final result = + (t.intValue(releaseOriginal: true) * 2).toJInteger(); + varCallbackResult.complete(result); + return result; + }, + manyPrimitives: (a, b, c, d) { + if (b) { + final result = a + c + d.toInt(); + manyPrimitivesResult.complete(result); + return result; + } else { + // Call self, add to [a] when [b] is false and change b to true. + return myInterface.manyPrimitives(a + 1, true, c, d); + } + }, + T: JInteger.type, + ), + ); + // [stringCallback] is going to be called first using [s]. + // The result of it is going to be used as the argument for + // [voidCallback]. + // The other two methods will be called individually using the passed + // arguments afterwards. + consume( + myInterface, + // For stringCallback: + 'hello'.toJString(), + // For manyPrimitives: + -1, + false, + 3, + 3.14, + // For varCallback + 7.toJInteger(), + ); + final voidCallback = await voidCallbackResult.future; + expect(voidCallback.toDartString(releaseOriginal: true), 'hellohello'); + + final varCallback = await varCallbackResult.future; + expect(varCallback.intValue(), 14); + + final manyPrimitives = await manyPrimitivesResult.future; + expect(manyPrimitives, -1 + 3 + 3.14.toInt() + 1); + + // Currently we have one implementation of the interface. + expect(MyInterface.$impls, hasLength(1)); + myInterface.release(); + // Running System.gc() and waiting. + _runJavaGC(); + for (var i = 0; i < 8; ++i) { + await Future.delayed(Duration(milliseconds: (1 << i) * 100)); + if (MyInterface.$impls.isEmpty) { + break; + } + } + // Since the interface is now deleted, the cleaner must signal to Dart + // to clean up. + expect(MyInterface.$impls, isEmpty); + }); + } + group('Dart exceptions are handled', () { + for (final exception in [UnimplementedError(), 'Hello!']) { + for (final sameThread in [true, false]) { + test( + 'on ${sameThread ? 'the same thread' : 'another thread'}' + ' throwing $exception', () async { + final runnable = MyRunnable.implement( + $MyRunnableImpl( + run: () { + throw exception; + }, + ), + ); + final runner = MyRunnableRunner(runnable); + if (sameThread) { + runner.runOnSameThread(); + } else { + runner.runOnAnotherThread(); + } + while (runner.error.isNull) { + await Future.delayed(const Duration(milliseconds: 100)); + } + expect( + Jni.env.IsInstanceOf( + runner.error.reference, + Jni.findClass('java/lang/reflect/UndeclaredThrowableException'), + ), + isTrue, + ); + final cause = runner.error.callMethodByName( + 'getCause', '()Ljava/lang/Throwable;', []); + expect( + Jni.env.IsInstanceOf( + cause.reference, + Jni.findClass( + 'com/github/dart_lang/jni/PortProxy\$DartException'), + ), + isTrue, + ); + expect(cause.toString(), contains(exception.toString())); + }); + } + } + }); + }); + + group('$groupName (load tests)', () { + const k4 = 4 * 1024; // This is a round number, unlike say 4000 + const k256 = 256 * 1024; + test('Create large number of JNI references without deleting', () { + for (int i = 0; i < k4; i++) { + final e = Example.new1(i); + expect(e.getNumber(), equals(i)); + } + }); + test('Create many JNI refs with scoped deletion', () { + for (int i = 0; i < k256; i++) { + using((arena) { + final e = Example.new1(i)..releasedBy(arena); + expect(e.getNumber(), equals(i)); + }); + } + }); + test('Create many JNI refs with scoped deletion, in batches', () { + for (int i = 0; i < 256; i++) { + using((arena) { + for (int i = 0; i < 1024; i++) { + final e = Example.new1(i)..releasedBy(arena); + expect(e.getNumber(), equals(i)); + } + }); + } + }); + test('Create large number of JNI refs with manual delete', () { + for (int i = 0; i < k256; i++) { + final e = Example.new1(i); + expect(e.getNumber(), equals(i)); + e.release(); + } + }); + test('Method returning primitive type does not create references', () { + using((arena) { + final e = Example.new1(64)..releasedBy(arena); + for (int i = 0; i < k256; i++) { + expect(e.getNumber(), equals(64)); + } + }); + }); + test('Class references are cached', () { + final asterisk = '*'.codeUnitAt(0); + for (int i = 0; i < k256; i++) { + expect(Fields.asterisk, equals(asterisk)); + } + }); + void testPassageOfTime(int n) { + test('Refs are not inadvertently deleted after $n seconds', () { + final f = Fields(); + expect(f.trillion, equals(trillion)); + sleep(Duration(seconds: n)); + expect(f.trillion, equals(trillion)); + }); + } + + if (!Platform.isAndroid) { + testPassageOfTime(1); + testPassageOfTime(4); + } + }); +} diff --git a/pkgs/jnigen/test/summary_generation_test.dart b/pkgs/jnigen/test/summary_generation_test.dart new file mode 100644 index 000000000..62eee3b8a --- /dev/null +++ b/pkgs/jnigen/test/summary_generation_test.dart @@ -0,0 +1,174 @@ +// Copyright (c) 2023, 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. + +// These tests validate summary generation in various scenarios. +// Currently, no validation of the summary content itself is done. + +@Tags(['summarizer_test']) + +import 'dart:math'; + +import 'package:jnigen/src/config/config.dart'; +import 'package:jnigen/src/elements/elements.dart'; +import 'package:jnigen/src/summary/summary.dart'; + +import 'package:path/path.dart' hide equals; +import 'package:test/test.dart'; + +import 'test_util/summary_util.dart'; +import 'test_util/test_util.dart'; + +const nestedClasses = [ + 'com.github.dart_lang.jnigen.simple_package.Example\$Nested', + 'com.github.dart_lang.jnigen.simple_package.Example\$Nested\$NestedTwice', + 'com.github.dart_lang.jnigen.generics.GrandParent\$StaticParent', + 'com.github.dart_lang.jnigen.generics.GrandParent\$StaticParent\$Child', + 'com.github.dart_lang.jnigen.generics.GrandParent\$Parent', + 'com.github.dart_lang.jnigen.generics.GrandParent\$Parent\$Child', +]; + +void expectSummaryHasAllClasses(Classes? classes) { + expect(classes, isNotNull); + final decls = classes!.decls; + expect(decls.entries.length, greaterThanOrEqualTo(javaFiles.length)); + final declNames = decls.keys.toSet(); + final expectedClasses = + javaClasses.where((name) => !name.contains("annotations.")).toList(); + // Nested classes should be included automatically with parent class. + // change this part if you change this behavior intentionally. + expectedClasses.addAll(nestedClasses); + expect(declNames, containsAll(expectedClasses)); +} + +/// Packs files indicated by [artifacts], each relative to [artifactDir] into +/// a JAR file at [jarPath]. +Future createJar({ + required String artifactDir, + required List artifacts, + required String jarPath, +}) async { + await runCommand( + 'jar', + ['cf', relative(jarPath, from: artifactDir), ...artifacts], + workingDirectory: artifactDir, + ); +} + +final random = Random.secure(); + +void testSuccessCase(String description, Config config) { + config.classes = summarizerClassesSpec; + test(description, () async { + final classes = await getSummary(config); + expectSummaryHasAllClasses(classes); + }); +} + +void testFailureCase( + String description, Config config, String nonExistingClass) { + test(description, () async { + final insertPosition = random.nextInt(config.classes.length + 1); + config.classes = summarizerClassesSpec.sublist(0, insertPosition) + + [nonExistingClass] + + summarizerClassesSpec.sublist(insertPosition); + try { + await getSummary(config); + } on SummaryParseException catch (e) { + expect(e.stderr, isNotNull); + expect(e.stderr!, stringContainsInOrder(["Not found", nonExistingClass])); + return; + } + throw AssertionError("No exception was caught"); + }); +} + +void testAllCases({ + List? sourcePath, + List? classPath, +}) { + testSuccessCase( + '- valid config', + getSummaryGenerationConfig(sourcePath: sourcePath, classPath: classPath), + ); + testFailureCase( + '- should fail with non-existing class', + getSummaryGenerationConfig(sourcePath: sourcePath, classPath: classPath), + 'com.github.dart_lang.jnigen.DoesNotExist', + ); + testFailureCase( + '- should fail with non-existing package', + getSummaryGenerationConfig(sourcePath: sourcePath, classPath: classPath), + 'com.github.dart_lang.notexist', + ); +} + +void main() async { + await checkLocallyBuiltDependencies(); + final tempDir = getTempDir("jnigen_summary_tests_"); + + group('Test summary generation from compiled JAR', () { + final targetDir = tempDir.createTempSync("compiled_jar_test_"); + final jarPath = join(targetDir.absolute.path, 'classes.jar'); + setUpAll(() async { + await compileJavaFiles(simplePackageDir, targetDir); + final classFiles = findFilesWithSuffix(targetDir, '.class'); + await createJar( + artifactDir: targetDir.path, artifacts: classFiles, jarPath: jarPath); + }); + testAllCases(classPath: [jarPath]); + }); + + group('Test summary generation from source JAR', () { + final targetDir = tempDir.createTempSync("source_jar_test_"); + final jarPath = join(targetDir.path, 'sources.jar'); + setUpAll(() async { + await createJar( + artifactDir: simplePackageDir.path, + artifacts: javaFiles, + jarPath: jarPath); + }); + testAllCases(sourcePath: [jarPath]); + }); + + group('Test summary generation from source folder', () { + testAllCases(sourcePath: [simplePackagePath]); + }); + + group('Test summary generation from compiled classes in directory', () { + final targetDir = tempDir.createTempSync("compiled_classes_test_"); + setUpAll(() => compileJavaFiles(simplePackageDir, targetDir)); + testAllCases(classPath: [targetDir.path]); + }); + + // Test summary generation from combination of a source and class path + group('Test summary generation from combination', () { + final targetDir = tempDir.createTempSync("combination_test_"); + final classesJarPath = join(targetDir.path, 'classes.jar'); + // remove a class from source files and create a source JAR + final sourceFiles = javaFiles.toList(); + sourceFiles.removeLast(); + final sourceJarPath = join(targetDir.path, 'sources.jar'); + setUpAll(() async { + await createJar( + artifactDir: simplePackageDir.path, + artifacts: sourceFiles, + jarPath: sourceJarPath, + ); + + await compileJavaFiles(simplePackageDir, targetDir); + final classFiles = findFilesWithSuffix(targetDir, '.class'); + await createJar( + artifactDir: targetDir.path, + artifacts: classFiles, + jarPath: classesJarPath, + ); + }); + testAllCases( + classPath: [classesJarPath], + sourcePath: [sourceJarPath], + ); + }); + + tearDownAll(() => deleteTempDirWithDelay(tempDir)); +} diff --git a/pkgs/jnigen/test/summary_test.dart b/pkgs/jnigen/test/summary_test.dart new file mode 100644 index 000000000..c83e798a3 --- /dev/null +++ b/pkgs/jnigen/test/summary_test.dart @@ -0,0 +1,323 @@ +// Copyright (c) 2023, 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. + +// These tests validate individual characteristics in summary +// For example, the values of methods, arguments, types, generic params etc... +@Tags(['summarizer_test']) + +import 'package:jnigen/src/elements/elements.dart'; +import 'package:jnigen/src/summary/summary.dart'; +import 'package:test/test.dart'; + +import 'test_util/summary_util.dart'; +import 'test_util/test_util.dart'; + +const jnigenPackage = 'com.github.dart_lang.jnigen'; +const simplePackage = "$jnigenPackage.simple_package"; + +extension on Classes { + String _getSimpleName(ClassDecl c) { + return c.binaryName.split(".").last; + } + + ClassDecl getClassBySimpleName(String simpleName) { + return decls.values.firstWhere((c) => _getSimpleName(c) == simpleName); + } + + ClassDecl getClass(String dirName, String className) { + return decls['$jnigenPackage.$dirName.$className']!; + } + + ClassDecl getExampleClass() { + return getClass('simple_package', 'Example'); + } +} + +extension on ClassDecl { + Method getMethod(String name) => methods.firstWhere((m) => m.name == name); + Field getField(String name) => fields.firstWhere((f) => f.name == name); +} + +void registerCommonTests(Classes classes) { + test('static modifier', () { + final example = classes.getExampleClass(); + final containsStatic = contains("static"); + final notContainsStatic = isNot(containsStatic); + expect(example.getMethod("max4").modifiers, containsStatic); + expect(example.getMethod("getCodename").modifiers, notContainsStatic); + expect(example.getField("ON").modifiers, containsStatic); + expect(example.getField("codename").modifiers, notContainsStatic); + final nested = classes.getClassBySimpleName("Example\$Nested"); + expect(nested.modifiers, containsStatic); + final nonStaticNested = + classes.getClassBySimpleName("Example\$NonStaticNested"); + expect(nonStaticNested.modifiers, notContainsStatic); + }); + + test('Public, protected and private modifiers', () { + final example = classes.getExampleClass(); + final hasPrivate = contains("private"); + final hasProtected = contains("protected"); + final hasPublic = contains("public"); + final isPrivate = allOf(hasPrivate, isNot(hasProtected), isNot(hasPublic)); + final isProtected = + allOf(isNot(hasPrivate), hasProtected, isNot(hasPublic)); + final isPublic = allOf(isNot(hasPrivate), isNot(hasProtected), hasPublic); + expect(example.getMethod("getNumber").modifiers, isPublic); + expect(example.getMethod("privateMethod").modifiers, isPrivate); + expect(example.getMethod("protectedMethod").modifiers, isProtected); + expect(example.getField("OFF").modifiers, isPublic); + expect(example.getField("number").modifiers, isPrivate); + expect(example.getField("protectedField").modifiers, isProtected); + }); + + test('final modifier', () { + final example = classes.getExampleClass(); + final isFinal = contains('final'); + expect(example.getField("PI").modifiers, isFinal); + expect(example.getField("unusedRandom").modifiers, isFinal); + expect(example.getField("number").modifiers, isNot(isFinal)); + expect(example.getMethod("finalMethod").modifiers, isFinal); + }); + + void assertToBeStringListType(TypeUsage listType) { + expect(listType.kind, equals(Kind.declared)); + final listClassType = listType.type as DeclaredType; + expect(listClassType.binaryName, equals('java.util.List')); + expect(listClassType.params, hasLength(1)); + final listTypeParam = listClassType.params[0]; + expect(listTypeParam.kind, equals(Kind.declared)); + expect(listTypeParam.type.name, equals('java.lang.String')); + } + + test('return types', () { + final example = classes.getExampleClass(); + expect(example.getMethod("getNumber").returnType.shorthand, equals("int")); + expect(example.getMethod("getName").returnType.shorthand, + equals("java.lang.String")); + expect(example.getMethod("getNestedInstance").returnType.name, + equals("$simplePackage.Example\$Nested")); + final listType = example.getMethod("getList").returnType; + assertToBeStringListType(listType); + }); + + test('parameter types', () { + final example = classes.getExampleClass(); + final joinStrings = example.getMethod('joinStrings'); + final listType = joinStrings.params[0].type; + assertToBeStringListType(listType); + final stringType = joinStrings.params[1].type; + expect(stringType.kind, Kind.declared); + expect((stringType.type as DeclaredType).binaryName, 'java.lang.String'); + }); + + test('Parameters of several types', () { + final example = classes.getExampleClass(); + final method = example.getMethod('methodWithSeveralParams'); + expect(method.typeParams, hasLength(1)); + expect(method.typeParams[0].name, 'T'); + expect(method.typeParams[0].bounds[0].name, 'java.lang.CharSequence'); + + final charParam = method.params[0]; + expect(charParam.type.kind, equals(Kind.primitive)); + expect(charParam.type.name, equals('char')); + + final stringParam = method.params[1]; + expect(stringParam.type.kind, equals(Kind.declared)); + expect((stringParam.type.type as DeclaredType).binaryName, + equals('java.lang.String')); + + final arrayParam = method.params[2]; + expect(arrayParam.type.kind, equals(Kind.array)); + expect((arrayParam.type.type as ArrayType).type.name, equals('int')); + + final typeVarParam = method.params[3]; + expect(typeVarParam.type.kind, equals(Kind.typeVariable)); + expect((typeVarParam.type.type as TypeVar).name, equals('T')); + + final listParam = method.params[4]; + expect(listParam.type.kind, equals(Kind.declared)); + final listType = (listParam.type.type as DeclaredType); + expect(listType.binaryName, equals('java.util.List')); + expect(listType.params, hasLength(1)); + final tType = listType.params[0]; + expect(tType.kind, Kind.typeVariable); + expect((tType.type as TypeVar).name, equals('T')); + + final wildcardMapParam = method.params[5]; + expect(wildcardMapParam.type.kind, equals(Kind.declared)); + final mapType = (wildcardMapParam.type.type as DeclaredType); + expect(mapType.binaryName, equals('java.util.Map')); + expect(mapType.params, hasLength(2)); + final strType = mapType.params[0]; + expect(strType.name, 'java.lang.String'); + // TODO(#141): Wildcard implementation. + /* + final wildcardType = mapType.params[1]; + expect(wildcardType.kind, equals(Kind.wildcard)); + expect((wildcardType.type as Wildcard).extendsBound?.name, + equals('java.lang.CharSequence')); + */ + }); + + test('superclass', () { + final baseClass = classes.getClass('inheritance', 'BaseClass'); + expect(baseClass.typeParams, hasLength(1)); + final typeParam = baseClass.typeParams.single; + expect(typeParam.bounds.map((b) => b.name).toList(), + ['java.lang.CharSequence']); + + final specific = classes.getClass('inheritance', 'SpecificDerivedClass'); + expect(specific.typeParams, hasLength(0)); + expect(specific.superclass, isNotNull); + final specificSuper = specific.superclass!.type as DeclaredType; + expect(specificSuper.params[0].type, isA()); + expect(specificSuper.params[0].type.name, equals('java.lang.String')); + + final generic = classes.getClass('inheritance', 'GenericDerivedClass'); + expect(generic.typeParams, hasLength(1)); + expect(generic.typeParams[0].name, equals('T')); + expect(generic.typeParams[0].bounds.map((b) => b.name).toList(), + ['java.lang.CharSequence']); + expect(generic.superclass, isNotNull); + final genericSuper = generic.superclass!.type as DeclaredType; + expect(genericSuper.params[0].type, isA()); + expect(genericSuper.params[0].type.name, equals('T')); + }); + + test('constructor is included', () { + final example = classes.getExampleClass(); + void assertOneCtorExistsWithArity(List paramTypes) { + final arityCtors = example.methods + .where( + (m) => m.name == '' && m.params.length == paramTypes.length) + .toList(); + expect(arityCtors, hasLength(1)); + final ctor = arityCtors[0]; + expect(ctor.params.map((p) => p.type.name), equals(paramTypes)); + } + + assertOneCtorExistsWithArity([]); + assertOneCtorExistsWithArity(['int']); + assertOneCtorExistsWithArity(['int', 'boolean']); + assertOneCtorExistsWithArity(['int', 'boolean', 'java.lang.String']); + }); + + test('Overloaded methods', () { + final methods = classes + .getExampleClass() + .methods + .where((m) => m.name == 'overloaded') + .toList(); + final signatures = + methods.map((m) => m.params.map((p) => p.type.name).toList()).toSet(); + expect( + signatures, + equals({ + [], + ['int'], + ['int', 'java.lang.String'], + ['java.util.List'], + ['java.util.List', 'java.lang.String'], + }), + ); + }); + + test('Declaration type (class vs interface vs enum)', () { + final example = classes.getExampleClass(); + expect(example.declKind, DeclKind.classKind); + final myInterface = classes.getClass('interfaces', 'MyInterface'); + expect(myInterface.declKind, DeclKind.interfaceKind); + final color = classes.getClass('simple_package', 'Color'); + expect(color.declKind, DeclKind.enumKind); + }); + + test('Enum values', () { + final example = classes.getExampleClass(); + expect(example.values, anyOf(isNull, isEmpty)); + final color = classes.getClass('simple_package', 'Color'); + const expectedEnumValues = { + 'RED', + 'BLUE', + 'BLACK', + 'GREEN', + 'YELLOW', + 'LIME' + }; + expect(color.values?.toSet(), expectedEnumValues); + }); + + test('Static final field values', () { + final example = classes.getExampleClass(); + expect(example.getField("ON").defaultValue, equals(1)); + expect(example.getField("OFF").defaultValue, equals(0)); + expect(example.getField("PI").defaultValue, closeTo(3.14159, 0.001)); + expect( + example.getField("SEMICOLON").defaultValue, equals(';'.codeUnitAt(0))); + expect(example.getField("SEMICOLON_STRING").defaultValue, equals(';')); + }); + + test('self referencing generic parameters', () { + final gp = classes.getClass('generics', 'GenericTypeParams'); + final typeParams = gp.typeParams; + expect(typeParams[0].name, equals('S')); + expect(typeParams[0].bounds.map((e) => e.name), ['java.lang.CharSequence']); + expect(typeParams[1].name, equals('K')); + final selfBound = typeParams[1].bounds[0]; + expect(selfBound.kind, Kind.declared); + expect(selfBound.name, + equals('com.github.dart_lang.jnigen.generics.GenericTypeParams')); + final selfBoundType = selfBound.type as DeclaredType; + expect(selfBoundType.params, hasLength(2)); + expect(selfBoundType.params.map((e) => e.name), ['S', 'K']); + expect(selfBoundType.params.map((e) => e.kind), + [Kind.typeVariable, Kind.typeVariable]); + }); +} + +void main() async { + await checkLocallyBuiltDependencies(); + + final tempDir = getTempDir("jnigen_summary_tests_"); + + final sourceConfig = + getSummaryGenerationConfig(sourcePath: [simplePackagePath]); + final parsedFromSource = await getSummary(sourceConfig); + + final targetDir = tempDir.createTempSync("compiled_classes_test_"); + await compileJavaFiles(simplePackageDir, targetDir); + final classConfig = getSummaryGenerationConfig(classPath: [targetDir.path]); + final parsedFromClasses = await getSummary(classConfig); + + group('source summary', () { + registerCommonTests(parsedFromSource); + }); + + group('compiled summary', () { + registerCommonTests(parsedFromClasses); + }); + + group('source-based summary features', () { + final classes = parsedFromSource; + test('Parameter names', () { + final example = classes.getExampleClass(); + final joinStrings = example.getMethod('joinStrings'); + expect( + joinStrings.params.map((p) => p.name).toList(), ['values', 'delim']); + final methodWithSeveralParams = + example.getMethod("methodWithSeveralParams"); + expect(methodWithSeveralParams.params.map((p) => p.name).toList(), + ['ch', 's', 'a', 't', 'lt', 'wm']); + }); + + test('Javadoc comment', () { + final example = classes.getExampleClass(); + final joinStrings = example.getMethod('joinStrings'); + expect(joinStrings.javadoc?.comment, + contains("Joins the strings in the list using the given delimiter.")); + }); + }); + + tearDownAll(() => tempDir.deleteSync(recursive: true)); +} diff --git a/pkgs/jnigen/test/test_util/bindings_test_setup.dart b/pkgs/jnigen/test/test_util/bindings_test_setup.dart new file mode 100644 index 000000000..c493ad144 --- /dev/null +++ b/pkgs/jnigen/test/test_util/bindings_test_setup.dart @@ -0,0 +1,77 @@ +// 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. + +// Tests on generated code. +// +// Both the simple java example & jackson core classes example have tests in +// same file, because the test runner will reuse the process, which leads to +// reuse of the old JVM with old classpath if we have separate tests with +// different classpaths. + +import 'dart:io'; + +import 'package:jni/jni.dart'; +import 'package:path/path.dart' hide equals; + +import 'test_util.dart'; + +final simplePackageTest = join('test', 'simple_package_test'); +final jacksonCoreTest = join('test', 'jackson_core_test'); +final kotlinTest = join('test', 'kotlin_test'); +final jniJar = join('build', 'jni_libs', 'jni.jar'); + +final simplePackageTestJava = join(simplePackageTest, 'java'); +final kotlinTestKotlin = join(kotlinTest, 'kotlin'); + +late Directory tempClassDir; + +Future bindingsTestSetup() async { + await runCommand('dart', [ + 'run', + 'jni:setup', + '-p', + 'jni', + '-s', + join(simplePackageTest, 'c_based', 'c_bindings'), + '-s', + join(kotlinTest, 'c_based', 'c_bindings'), + '-s', + join(jacksonCoreTest, 'third_party', 'c_based', 'c_bindings'), + ]); + tempClassDir = + Directory.current.createTempSync("jnigen_runtime_test_classpath_"); + await compileJavaFiles(Directory(simplePackageTestJava), tempClassDir); + await runCommand('dart', [ + 'run', + 'jnigen:download_maven_jars', + '--config', + join(jacksonCoreTest, 'jnigen.yaml') + ]); + + final jacksonJars = await getJarPaths(join(jacksonCoreTest, 'third_party')); + + await runCommand( + 'mvn', + ['package'], + workingDirectory: kotlinTestKotlin, + runInShell: true, + ); + // Jar including Kotlin runtime and dependencies. + final kotlinTestJar = + join(kotlinTestKotlin, 'target', 'kotlin_test-jar-with-dependencies.jar'); + + if (!Platform.isAndroid) { + Jni.spawn(dylibDir: join('build', 'jni_libs'), classPath: [ + jniJar, + tempClassDir.path, + ...jacksonJars, + kotlinTestJar, + ]); + } + Jni.initDLApi(); +} + +void bindingsTestTeardown() { + tempClassDir.deleteSync(recursive: true); +} diff --git a/pkgs/jnigen/test/test_util/callback_types.dart b/pkgs/jnigen/test/test_util/callback_types.dart new file mode 100644 index 000000000..3b3356e7d --- /dev/null +++ b/pkgs/jnigen/test/test_util/callback_types.dart @@ -0,0 +1,12 @@ +// 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. + +// These definitions could be in `test_util` but these are imported by android +// integration tests, and we test_util imports several parts of package:jnigen. + +typedef TestCaseCallback = void Function(); +typedef TestRunnerCallback = void Function( + String description, + TestCaseCallback test, +); diff --git a/pkgs/jnigen/test/test_util/summary_util.dart b/pkgs/jnigen/test/test_util/summary_util.dart new file mode 100644 index 000000000..0d445837c --- /dev/null +++ b/pkgs/jnigen/test/test_util/summary_util.dart @@ -0,0 +1,75 @@ +// Copyright (c) 2023, 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. + +import 'dart:io'; + +import 'package:jnigen/src/config/config.dart'; +import 'package:jnigen/src/logging/logging.dart'; +import 'package:logging/logging.dart'; +import 'package:path/path.dart'; + +import 'test_util.dart'; + +String getClassNameFromPath(String path) { + if (!path.endsWith('.java')) { + throw ArgumentError('Filename must end with java'); + } + return path + .replaceAll('/', '.') + .replaceAll('\\', '.') + .substring(0, path.length - 5); +} + +/// test/simple_package_test/java +final simplePackagePath = join('test', 'simple_package_test', 'java'); + +/// Directory(test/simple_package_test/java) +final simplePackageDir = Directory(simplePackagePath); + +/// All Java files in simple_package_test/java +final javaFiles = findFilesWithSuffix(simplePackageDir, '.java'); + +/// All Java classes in simple_package_test/java +final javaClasses = javaFiles.map(getClassNameFromPath).toList(); + +// Remove individual class listings from one package, +// and add the package name instead, for testing. + +const removalPackageForSummaryTests = 'com.github.dart_lang.jnigen.pkg2'; + +/// List of FQNs passed to summarizer for simple_package_test. +final summarizerClassesSpec = [ + ...javaClasses.where((e) => !e.startsWith('$removalPackageForSummaryTests.')), + removalPackageForSummaryTests, +]; + +Config getSummaryGenerationConfig( + {List? sourcePath, List? classPath}) { + return Config( + outputConfig: OutputConfig( + bindingsType: BindingsType.dartOnly, + dartConfig: DartCodeOutputConfig( + path: Uri.file('unused.dart'), + structure: OutputStructure.singleFile, + ), + ), + // Make a defensive copy of class list, if some test mutates the list... + classes: summarizerClassesSpec.toList(), + sourcePath: sourcePath?.map((e) => Uri.file(e)).toList(), + classPath: classPath?.map((e) => Uri.file(e)).toList(), + logLevel: Level.WARNING, + ); +} + +void deleteTempDirWithDelay(Directory directory) { + try { + if (Platform.isWindows) { + // This appears to avoid "file used by another process" errors. + sleep(const Duration(seconds: 1)); + } + directory.deleteSync(recursive: true); + } on FileSystemException catch (e) { + log.warning("Cannot delete directory: $e"); + } +} diff --git a/pkgs/jnigen/test/test_util/test_util.dart b/pkgs/jnigen/test/test_util/test_util.dart new file mode 100644 index 000000000..3c418abc3 --- /dev/null +++ b/pkgs/jnigen/test/test_util/test_util.dart @@ -0,0 +1,248 @@ +// 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. + +import 'dart:io'; + +import 'package:jnigen/jnigen.dart'; +import 'package:jnigen/src/util/find_package.dart'; +import 'package:path/path.dart' hide equals; +import 'package:test/test.dart'; +import 'package:logging/logging.dart' show Level; + +import 'package:jnigen/src/logging/logging.dart'; + +final _currentDirectory = Directory("."); + +// If changing these constants, grep for these values. In some places, test +// package expects string literals. +const largeTestTag = 'large_test'; +const summarizerTestTag = 'summarizer_test'; + +Directory getTempDir(String prefix) { + return _currentDirectory.createTempSync(prefix); +} + +Future isEmptyOrNotExistDir(String path) async { + final dir = Directory(path); + return (!await dir.exists()) || (await dir.list().length == 0); +} + +/// Runs command, and prints output only if the exit status is non-zero. +Future runCommandReturningStatus(String exec, List args, + {String? workingDirectory, bool runInShell = false}) async { + final proc = await Process.run(exec, args, + workingDirectory: workingDirectory, runInShell: runInShell); + if (proc.exitCode != 0) { + printError('command exited with exit status ${proc.exitCode}:\n' + '$exec ${args.join(" ")}\n'); + printError(proc.stdout); + printError(proc.stderr); + } + return proc.exitCode; +} + +Future runCommand( + String exec, + List args, { + String? workingDirectory, + bool runInShell = false, + String? messageOnFailure, +}) async { + final status = await runCommandReturningStatus( + exec, + args, + workingDirectory: workingDirectory, + runInShell: runInShell, + ); + if (status != 0) { + final message = messageOnFailure ?? 'Failed to execute $exec'; + throw Exception('$message: Command exited with return code $status'); + } +} + +/// List all JAR files in [testRoot]/jar +Future> getJarPaths(String testRoot) async { + final jarPath = join(testRoot, 'jar'); + if (!await Directory(jarPath).exists()) { + return []; + } + return Directory(jarPath) + .list() + .map((entry) => entry.path) + .where((path) => path.endsWith('.jar')) + .toList(); +} + +/// Read file normalizing CRLF to LF. +String readFile(File file) => file.readAsStringSync().replaceAll('\r\n', '\n'); + +/// Compares 2 hierarchies using `git diff --no-index`. +void comparePaths(String path1, String path2) { + final diffCommand = [ + "diff", + "--no-index", + if (stderr.supportsAnsiEscapes) "--color=always", + ]; + final diffProc = Process.runSync("git", [...diffCommand, path1, path2]); + if (diffProc.exitCode != 0) { + final originalDiff = diffProc.stdout; + log.warning( + "Paths $path1 and $path2 differ, Running dart format on $path1."); + Process.runSync('dart', ['format', path1]); + final fallbackDiffProc = + Process.runSync("git", [...diffCommand, path1, path2]); + if (fallbackDiffProc.exitCode != 0) { + stderr.writeln(originalDiff); + throw Exception("Paths $path1 and $path2 differ"); + } + } +} + +Future _generateTempBindings(Config config, Directory tempDir) async { + final tempSrc = tempDir.uri.resolve("src/"); + final singleFile = + config.outputConfig.dartConfig.structure == OutputStructure.singleFile; + final tempLib = singleFile + ? tempDir.uri.resolve("generated.dart") + : tempDir.uri.resolve("lib/"); + if (config.outputConfig.bindingsType == BindingsType.cBased) { + config.outputConfig.cConfig!.path = tempSrc; + } + config.outputConfig.dartConfig.path = tempLib; + config.logLevel = Level.WARNING; + await generateJniBindings(config); +} + +/// Generates and compares bindings with reference bindings. +/// +/// [dartReferenceBindings] can be directory or file depending on output +/// configuration. +/// +/// If the config generates C code, [cReferenceBindings] must be a non-null +/// directory path. +Future generateAndCompareBindings(Config config) async { + final dartReferenceBindings = + config.outputConfig.dartConfig.path.toFilePath(); + final cReferenceBindings = config.outputConfig.cConfig?.path.toFilePath(); + final currentDir = Directory.current; + final tempDir = currentDir.createTempSync("jnigen_test_temp"); + final tempSrc = tempDir.uri.resolve("src/"); + final singleFile = + config.outputConfig.dartConfig.structure == OutputStructure.singleFile; + final tempLib = singleFile + ? tempDir.uri.resolve("generated.dart") + : tempDir.uri.resolve("lib/"); + try { + await _generateTempBindings(config, tempDir); + comparePaths(dartReferenceBindings, tempLib.toFilePath()); + if (config.outputConfig.bindingsType == BindingsType.cBased) { + comparePaths(cReferenceBindings!, tempSrc.toFilePath()); + } + } finally { + tempDir.deleteSync(recursive: true); + } +} + +Future generateAndAnalyzeBindings(Config config) async { + final tempDir = Directory.current.createTempSync("jnigen_test_temp"); + try { + await _generateTempBindings(config, tempDir); + final analyzeResult = Process.runSync("dart", ["analyze", tempDir.path]); + expect(analyzeResult.exitCode, equals(0), + reason: "Analyzer exited with non-zero status"); + } finally { + tempDir.deleteSync(recursive: true); + } +} + +final summarizerJar = join('.', '.dart_tool', 'jnigen', 'ApiSummarizer.jar'); + +Future failIfSummarizerNotBuilt() async { + final jarExists = await File(summarizerJar).exists(); + if (!jarExists) { + stderr.writeln(); + log.fatal('Please build summarizer by running ' + '`dart run jnigen:setup` and try again'); + } + final isJarStale = jarExists && + await isPackageModifiedAfter( + 'jnigen', await File(summarizerJar).lastModified(), 'java/'); + if (isJarStale) { + stderr.writeln(); + log.fatal('Summarizer is not rebuilt after recent changes. ' + 'Please run `dart run jnigen:setup` and try again.'); + } +} + +const bindingTests = [ + 'jackson_core_test', + 'simple_package_test', + 'kotlin_test', +]; + +const registrantName = 'runtime_test_registrant.dart'; +const replicaName = 'runtime_test_registrant_dartonly_generated.dart'; + +void warnIfRuntimeTestsAreOutdated() { + final runtimeTests = join('test', 'generated_runtime_test.dart'); + if (!File(runtimeTests).existsSync()) { + log.fatal('Runtime test files not found. To run binding ' + 'runtime tests, please generate them by running ' + '`dart run tool/generate_runtime_tests.dart`'); + } + const regenInstr = 'Please run `dart run tool/generate_runtime_tests.dart` ' + 'and try again.'; + for (var testName in bindingTests) { + final registrant = File(join('test', testName, registrantName)); + final replica = File(join('test', testName, replicaName)); + if (!replica.existsSync()) { + log.fatal( + 'One or more generated runtime tests do not exist. $regenInstr', + ); + } + if (replica.lastModifiedSync().isBefore(registrant.lastModifiedSync())) { + log.fatal( + 'One or more generated runtime tests are not up-to-date. $regenInstr', + ); + } + } +} + +/// Verifies if locally built dependencies (currently `ApiSummarizer`) +/// are up-to-date. +Future checkLocallyBuiltDependencies() async { + await failIfSummarizerNotBuilt(); + warnIfRuntimeTestsAreOutdated(); +} + +void generateAndCompareBothModes( + String description, + Config cBasedConfig, + Config dartOnlyConfig, +) { + test('$description (cBased)', () async { + await generateAndCompareBindings(cBasedConfig); + }); + test('$description (dartOnly)', () async { + await generateAndCompareBindings(dartOnlyConfig); + }); +} + +List findFilesWithSuffix(Directory dir, String suffix) { + return dir + .listSync(recursive: true) + .map((entry) => relative(entry.path, from: dir.path)) + .where((path) => path.endsWith(suffix)) + .toList(); +} + +Future compileJavaFiles(Directory root, Directory target) async { + final javaFiles = findFilesWithSuffix(root, '.java'); + await runCommand( + 'javac', + ['-d', target.absolute.path, ...javaFiles], + workingDirectory: root.path, + messageOnFailure: 'Cannot compile java sources', + ); +} diff --git a/pkgs/jnigen/tool/command_runner.dart b/pkgs/jnigen/tool/command_runner.dart new file mode 100644 index 000000000..7bf925ea8 --- /dev/null +++ b/pkgs/jnigen/tool/command_runner.dart @@ -0,0 +1,109 @@ +import 'dart:io'; + +const ansiRed = '\x1b[31m'; +const ansiDefault = '\x1b[39;49m'; + +void printError(Object? message) { + if (stderr.supportsAnsiEscapes) { + message = '$ansiRed$message$ansiDefault'; + } + stderr.writeln(message); +} + +class StepFailure implements Exception { + StepFailure(this.name); + String name; + @override + String toString() => 'step failed: $name'; +} + +abstract class Step { + /// Runs this step, raises an exception if something fails. + Future run(); +} + +class Callback implements Step { + Callback(this.name, this.function); + String name; + Future Function() function; + @override + Future run() => function(); +} + +class Command implements Step { + Command(this.exec, this.args, this.workingDirectory); + final String exec; + final List args; + final Uri workingDirectory; + + @override + Future run() async { + final result = await Process.run( + exec, + args, + workingDirectory: workingDirectory.toFilePath(), + runInShell: true, + ); + if (result.exitCode != 0) { + printError(result.stdout); + printError(result.stderr); + final commandString = "$exec ${args.join(" ")}"; + stderr.writeln("failure executing command: $commandString"); + throw StepFailure(commandString); + } + } +} + +class Runner { + static final gitRoot = getRepositoryRoot(); + Runner(this.name, this.defaultWorkingDir); + String name; + Uri defaultWorkingDir; + final steps = []; + final cleanupSteps = []; + + void chainCommand(String exec, List args, {Uri? workingDirectory}) => + _addCommand(steps, exec, args, workingDirectory: workingDirectory); + + void chainCleanupCommand(String exec, List args, + {Uri? workingDirectory}) => + _addCommand(cleanupSteps, exec, args, workingDirectory: workingDirectory); + + void _addCommand(List list, String exec, List args, + {Uri? workingDirectory}) { + list.add(Command(exec, args, (workingDirectory ?? defaultWorkingDir))); + } + + void chainCallback(String name, Future Function() callback) { + steps.add(Callback(name, callback)); + } + + Future run() async { + stderr.writeln("started: $name"); + var error = false; + for (var step in steps) { + try { + await step.run(); + } on StepFailure catch (e) { + stderr.writeln(e); + error = true; + exitCode = 1; + break; + } + } + stderr.writeln('${error ? "failed" : "complete"}: $name'); + for (var step in cleanupSteps) { + try { + await step.run(); + } on Exception catch (e) { + printError("ERROR: $e"); + } + } + } +} + +Uri getRepositoryRoot() { + final gitCommand = Process.runSync("git", ["rev-parse", "--show-toplevel"]); + final output = gitCommand.stdout as String; + return Uri.directory(output.trim()); +} diff --git a/pkgs/jnigen/tool/generate_runtime_tests.dart b/pkgs/jnigen/tool/generate_runtime_tests.dart new file mode 100644 index 000000000..75a1ea2fb --- /dev/null +++ b/pkgs/jnigen/tool/generate_runtime_tests.dart @@ -0,0 +1,183 @@ +// Copyright (c) 2023, 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. + +import 'dart:io'; + +import 'package:path/path.dart'; +import 'package:args/args.dart'; + +import 'package:jnigen/src/logging/logging.dart'; + +final lineBreak = Platform.isWindows ? '\r\n' : '\n'; + +void runCommand(String exec, List args) { + final proc = Process.runSync(exec, args, runInShell: true); + log.info('Execute $exec ${args.join(" ")}'); + if (proc.exitCode != 0) { + exitCode = proc.exitCode; + printError(proc.stdout); + printError(proc.stderr); + throw Exception('Command failed: $exec ${args.join(" ")}'); + } +} + +const testPath = 'test'; +const registrantFileName = 'runtime_test_registrant.dart'; +const dartOnlyRegistrantFileName = + 'runtime_test_registrant_dartonly_generated.dart'; + +// Paths of generated files, should not be checked in. +// If you change this, add the corresponding entry to .gitignore as well. +const replicaSuffix = '_dartonly_generated.dart'; +final runnerFilePath = join(testPath, 'generated_runtime_test.dart'); +final androidRunnerFilePath = + join('android_test_runner', 'integration_test', 'runtime_test.dart'); + +final generatedComment = + '// Generated file. Do not edit or check-in to version control.$lineBreak'; +const copyright = ''' +// Copyright (c) 2023, 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. +'''; + +const bindingTests = [ + 'jackson_core_test', + 'simple_package_test', + 'kotlin_test', +]; + +const hasThirdPartyDir = {'jackson_core_test'}; + +final _generatedFiles = [ + for (var testName in bindingTests) + join(testPath, testName, dartOnlyRegistrantFileName), + runnerFilePath, + androidRunnerFilePath, +]; + +void generateReplicasAndRunner() { + final imports = {}; + for (var testName in bindingTests) { + final registrant = join(testName, registrantFileName); + final registrantFile = File(join(testPath, registrant)); + final contents = registrantFile + .readAsStringSync() + .replaceAll('c_based/dart_bindings/', 'dart_only/dart_bindings/'); + + final replica = registrant.replaceAll('.dart', replicaSuffix); + final replicaFile = File(join(testPath, replica)); + replicaFile.writeAsStringSync('$generatedComment$lineBreak$contents'); + log.info('Generated $replica'); + imports['${testName}_c_based'] = + Uri.file(registrant).toFilePath(windows: false); + imports['${testName}_dart_only'] = + Uri.file(replica).toFilePath(windows: false); + } + final importStrings = imports.entries + .map((e) => 'import "${e.value}" as ${e.key};') + .join(lineBreak); + final androidImportStrings = imports.entries + .map((e) => 'import "../../test/${e.value}" as ${e.key};') + .join(lineBreak); + final runStrings = imports.keys + .map((name) => '$name.registerTests("$name", test);') + .join('$lineBreak '); + final runnerProgram = ''' +$generatedComment +$copyright +import 'package:test/test.dart'; +import 'test_util/bindings_test_setup.dart' as setup; + +$importStrings + +void main() { + setUpAll(setup.bindingsTestSetup); + $runStrings + tearDownAll(setup.bindingsTestTeardown); +} +'''; + final runnerFile = File(runnerFilePath); + runnerFile.writeAsStringSync(runnerProgram); + log.info('Generated runner $runnerFilePath'); + + final androidRunnerProgram = ''' +$generatedComment +$copyright +import "package:flutter_test/flutter_test.dart"; +import "package:jni/jni.dart"; + +$androidImportStrings + +typedef TestCaseCallback = void Function(); + +void test(String description, TestCaseCallback testCase) { + testWidgets(description, (widgetTester) async => testCase()); +} + +void main() { + Jni.initDLApi(); + $runStrings +} +'''; + File(androidRunnerFilePath).writeAsStringSync(androidRunnerProgram); + log.info('Generated android runner: $androidRunnerFilePath'); + + final cMakePath = + join('android_test_runner', 'android', 'app', 'CMakeLists.txt'); + + final cmakeSubdirs = bindingTests.map((testName) { + final indirect = hasThirdPartyDir.contains(testName) ? '/third_party' : ''; + return 'add_subdirectory' + '(../../../test/$testName$indirect/c_based/c_bindings ' + '${testName}_build)'; + }).join(lineBreak); + final cMakeConfig = ''' +## Parent CMake for Android native build target. This will build +## all C bindings from tests. + +cmake_minimum_required(VERSION 3.10) + +project(simple_package VERSION 0.0.1 LANGUAGES C) + +$cmakeSubdirs +'''; + File(cMakePath).writeAsStringSync(cMakeConfig); + log.info('Wrote Android CMake file: $cMakePath'); +} + +void cleanup() { + for (var path in _generatedFiles) { + File(path).deleteSync(); + log.info('Deleted $path'); + } +} + +void main(List args) async { + final parser = ArgParser() + ..addFlag( + 'help', + abbr: 'h', + help: 'show help', + negatable: false, + ) + ..addFlag( + 'clean', + abbr: 'c', + help: 'clear generated files', + negatable: false, + ); + final argResults = parser.parse(args); + if (argResults['help']) { + stderr.writeln( + 'Generates runtime tests for both Dart-only and C based bindings.'); + stderr.writeln(parser.usage); + return; + } else if (argResults['clean']) { + cleanup(); + } else { + generateReplicasAndRunner(); + runCommand('dart', ['format', ..._generatedFiles]); + } +} diff --git a/pkgs/jnigen/tool/pr_checks.dart b/pkgs/jnigen/tool/pr_checks.dart new file mode 100644 index 000000000..3e983c244 --- /dev/null +++ b/pkgs/jnigen/tool/pr_checks.dart @@ -0,0 +1,180 @@ +// 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. + +// This is a script to run a subset of CI checks on development machine before +// submitting PR. This prevents from accidentally forgetting to format or +// remove an unused import. + +// This is rough around the edges. This script may give false positives such +// as some gitignore'd temporary files failing the comparison. + +// On windows, please install 'diffutils' using your favorite package installer +// for this script to work correctly. Also ensure that clang-format is on your +// PATH. + +import 'dart:async'; +import 'dart:io'; + +import 'package:args/args.dart'; + +import 'command_runner.dart'; + +// Flags +const _clone = 'clone'; + +void main(List arguments) async { + final parser = ArgParser() + ..addFlag( + _clone, + help: 'Run checks in a cloned copy of the project.', + defaultsTo: true, + negatable: true, + ); + final argResults = parser.parse(arguments); + final shouldClone = argResults[_clone] as bool; + final gitRoot = getRepositoryRoot(); + + // change to project root + Directory.current = gitRoot.toFilePath(); + + var tempDir = Directory.current; + if (shouldClone) { + tempDir = Directory.current.createTempSync('jnigen_checks_clone_'); + final gitClone = Runner("Clone jni", Directory.current.uri) + ..chainCommand('git', ['clone', '.', tempDir.path]); + await gitClone.run(); + } + + final jniPath = tempDir.uri.resolve("jni/"); + final jnigenPath = tempDir.uri.resolve("jnigen/"); + final pubGet = Runner("Pub get", tempDir.uri) + ..chainCommand("flutter", ["pub", "get", "--offline"], + workingDirectory: jniPath) + ..chainCommand("dart", ["pub", "get", "--offline"], + workingDirectory: jnigenPath); + await pubGet.run(); + + final jniAnalyze = Runner("Analyze JNI", jniPath); + jniAnalyze + ..chainCommand("dart", ["analyze", "--fatal-infos"]) + ..chainCommand( + "dart", ["format", "--output=none", "--set-exit-if-changed", "."]) + ..chainCommand( + "clang-format", + [ + "--dry-run", + "-Werror", + "dartjni.c", + "dartjni.h", + "third_party/global_jni_env.c", + "third_party/global_jni_env.h", + ], + workingDirectory: jniPath.resolve("src/")); + final jniTest = Runner("Test JNI", jniPath) + ..chainCommand("dart", ["run", "jni:setup"]) + ..chainCommand("dart", ["test", "-j", "1"]); + unawaited(jniAnalyze.run().then((f) => jniTest.run())); + + List getJavaFiles(String relativePath) => + Directory.fromUri(jnigenPath.resolve(relativePath)) + .listSync(recursive: true) + .where((file) => file.path.endsWith(".java")) + .map((file) => file.path) + .toList(); + + final javaFiles = getJavaFiles("java/") + + getJavaFiles("test/simple_package_test") + + getJavaFiles("example/in_app_java") + + getJavaFiles("example/notification_plugin"); + + 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); + final oldBindingsText = ffigenBindings.readAsStringSync(); + final ffigenCompare = Runner("Generate & Compare FFIGEN bindings", jniPath) + ..chainCommand("dart", ["run", "ffigen", "--config", "ffigen.yaml"]) + ..chainCallback("compare bindings", () async { + final newBindingsText = await ffigenBindings.readAsString(); + if (newBindingsText != oldBindingsText) { + await ffigenBindings.writeAsString(oldBindingsText); + throw "new JNI.h bindings differ from old bindings"; + } + }); + unawaited(ffigenCompare.run()); + + final jnigenAnalyze = Runner("Analyze jnigen", jnigenPath) + ..chainCommand("dart", ["analyze", "--fatal-infos"]) + ..chainCommand( + "dart", ["format", "--output=none", "--set-exit-if-changed", "."]) + ..chainCommand("dart", ["run", "jnigen:setup"]); + + // Tests may need more time when running on systems with less cores. + // So '--timeout 2x' is specified. + final jnigenTest = Runner("Test jnigen", gitRoot.resolve("jnigen/")) + ..chainCommand("dart", ["test", "--timeout", "2x"]); + + // Note: Running in_app_java and notification_plugin checks on source dir + // itself, because running flutter build in cloned dir will take time. + final compareInAppJavaBindings = Runner( + "Generate & compare InAppJava bindings", + gitRoot.resolve("jnigen/example/in_app_java")) + ..chainCommand("dart", [ + "run", + "jnigen", + "--config", + "jnigen.yaml", + "-Doutput.c.path=src_temp/", + "-Doutput.dart.path=_temp.dart", + ]) + ..chainCommand("diff", ["lib/android_utils.dart", "_temp.dart"]) + ..chainCommand("diff", ["-qr", "src/android_utils/", "src_temp/"]) + ..chainCleanupCommand("rm", ["-r", "_temp.dart", "src_temp"]); + + final comparePdfboxBindings = Runner("Generate & compare PdfBox Bindings", + gitRoot.resolve("jnigen/example/pdfbox_plugin")) + ..chainCommand("dart", [ + "run", + "jnigen", + "--config", + "jnigen.yaml", + "-Doutput.c.path=src_temp/", + "-Doutput.dart.path=lib_temp/", + ]) + ..chainCommand("diff", ["-qr", "lib/src/third_party/", "lib_temp/"]) + ..chainCommand("diff", ["-qr", "src/", "src_temp/"]) + ..chainCleanupCommand("rm", ["-r", "lib_temp", "src_temp"]); + + final compareNotificationPluginBindings = Runner( + "Generate & compare NotificationPlugin Bindings", + gitRoot.resolve("jnigen/example/notification_plugin")) + ..chainCommand("dart", [ + "run", + "jnigen", + "--config", + "jnigen.yaml", + "-Doutput.c.path=src_temp/", + "-Doutput.dart.path=_temp.dart", + ]) + ..chainCommand("diff", ["lib/notifications.dart", "_temp.dart"]) + ..chainCommand("diff", ["-qr", "src/", "src_temp/"]) + ..chainCleanupCommand("rm", ["-r", "_temp.dart", "src_temp"]); + + unawaited(jnigenAnalyze.run().then((_) { + final test = jnigenTest.run(); + final inAppJava = compareInAppJavaBindings.run(); + final pdfBox = comparePdfboxBindings.run(); + final notificationPlugin = compareNotificationPluginBindings.run(); + return Future.wait([test, inAppJava, pdfBox, notificationPlugin]); + }).then((_) { + if (shouldClone) { + tempDir.deleteSync(recursive: true); + } + })); +} diff --git a/pkgs/jnigen/tool/regenerate_all_bindings.dart b/pkgs/jnigen/tool/regenerate_all_bindings.dart new file mode 100644 index 000000000..19b764287 --- /dev/null +++ b/pkgs/jnigen/tool/regenerate_all_bindings.dart @@ -0,0 +1,41 @@ +// 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. + +// Run this script after any change which affects generated bindings. +// +// This will update all generated bindings in the whole repository. + +import 'dart:io'; + +import 'command_runner.dart'; + +const scripts = [ + "test/jackson_core_test/generate.dart", + "test/simple_package_test/generate.dart", + "test/kotlin_test/generate.dart", +]; + +const yamlBasedExamples = [ + "example/in_app_java", + "example/pdfbox_plugin", + "example/notification_plugin", + "example/kotlin_plugin", +]; + +void main() async { + final runners = []; + final current = Directory.current.uri; + for (var script in scripts) { + runners.add(Runner("Run generate script: $script", current) + ..chainCommand("dart", ["run", script])); + } + + for (var yamlDir in yamlBasedExamples) { + runners.add( + Runner("Regenerate bindings in $yamlDir", current.resolve(yamlDir)) + ..chainCommand("dart", ["run", "jnigen", "--config", "jnigen.yaml"])); + } + + await Future.wait(runners.map((runner) => runner.run()).toList()); +}