[jnigen] Use .jar metadata to generate generic types (https://github.com/dart-lang/jnigen/issues/158)

Closes https://github.com/dart-lang/jnigen/issues/132.

ASM backend, parses classes, fields and method signatures from the metadata to add generic type information to other-wise type-erased generics.
diff --git a/pkgs/jnigen/example/in_app_java/jnigen.yaml b/pkgs/jnigen/example/in_app_java/jnigen.yaml
index e344270..f77215b 100644
--- a/pkgs/jnigen/example/in_app_java/jnigen.yaml
+++ b/pkgs/jnigen/example/in_app_java/jnigen.yaml
@@ -14,3 +14,4 @@
 classes:
   - 'com.example.in_app_java.AndroidUtils' # from 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
index 1b6cc08..6929631 100644
--- a/pkgs/jnigen/example/in_app_java/lib/android_utils.dart
+++ b/pkgs/jnigen/example/in_app_java/lib/android_utils.dart
@@ -407,3 +407,400 @@
     (this as jni.JArray<jni.JObject>)[index] = value;
   }
 }
+
+/// from: java.util.HashMap
+class HashMap<K extends jni.JObject, V extends jni.JObject>
+    extends jni.JObject {
+  late final jni.JObjType? _$type;
+  @override
+  jni.JObjType get $type => _$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 _ctor = jniLookup<
+              ffi.NativeFunction<jni.JniResult Function(ffi.Int32, ffi.Float)>>(
+          "HashMap__ctor")
+      .asFunction<jni.JniResult Function(int, double)>();
+
+  /// from: public void <init>(int i, float f)
+  HashMap(this.$K, this.$V, int i, double f)
+      : super.fromRef(_ctor(i, f).object);
+
+  static final _ctor1 =
+      jniLookup<ffi.NativeFunction<jni.JniResult Function(ffi.Int32)>>(
+              "HashMap__ctor1")
+          .asFunction<jni.JniResult Function(int)>();
+
+  /// from: public void <init>(int i)
+  HashMap.ctor1(this.$K, this.$V, int i) : super.fromRef(_ctor1(i).object);
+
+  static final _ctor2 =
+      jniLookup<ffi.NativeFunction<jni.JniResult Function()>>("HashMap__ctor2")
+          .asFunction<jni.JniResult Function()>();
+
+  /// from: public void <init>()
+  HashMap.ctor2(this.$K, this.$V) : super.fromRef(_ctor2().object);
+
+  static final _ctor3 = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(ffi.Pointer<ffi.Void>)>>("HashMap__ctor3")
+      .asFunction<jni.JniResult Function(ffi.Pointer<ffi.Void>)>();
+
+  /// from: public void <init>(java.util.Map map)
+  HashMap.ctor3(this.$K, this.$V, jni.JObject map)
+      : super.fromRef(_ctor3(map.reference).object);
+
+  static final _size = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(ffi.Pointer<ffi.Void>)>>("HashMap__size")
+      .asFunction<jni.JniResult Function(ffi.Pointer<ffi.Void>)>();
+
+  /// from: public int size()
+  int size() => _size(reference).integer;
+
+  static final _isEmpty = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(
+                  ffi.Pointer<ffi.Void>)>>("HashMap__isEmpty")
+      .asFunction<jni.JniResult Function(ffi.Pointer<ffi.Void>)>();
+
+  /// from: public boolean isEmpty()
+  bool isEmpty() => _isEmpty(reference).boolean;
+
+  static final _get0 = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>)>>("HashMap__get0")
+      .asFunction<
+          jni.JniResult Function(
+              ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>();
+
+  /// from: public V get(java.lang.Object object)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  V get0(jni.JObject object) =>
+      $V.fromRef(_get0(reference, object.reference).object);
+
+  static final _containsKey = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>)>>("HashMap__containsKey")
+      .asFunction<
+          jni.JniResult Function(
+              ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>();
+
+  /// from: public boolean containsKey(java.lang.Object object)
+  bool containsKey(jni.JObject object) =>
+      _containsKey(reference, object.reference).boolean;
+
+  static final _put = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>)>>("HashMap__put")
+      .asFunction<
+          jni.JniResult Function(ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>,
+              ffi.Pointer<ffi.Void>)>();
+
+  /// from: public V put(K object, V object1)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  V put(K object, V object1) =>
+      $V.fromRef(_put(reference, object.reference, object1.reference).object);
+
+  static final _putAll = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>)>>("HashMap__putAll")
+      .asFunction<
+          jni.JniResult Function(
+              ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>();
+
+  /// from: public void putAll(java.util.Map map)
+  void putAll(jni.JObject map) => _putAll(reference, map.reference).check();
+
+  static final _remove = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>)>>("HashMap__remove")
+      .asFunction<
+          jni.JniResult Function(
+              ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>();
+
+  /// from: public V remove(java.lang.Object object)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  V remove(jni.JObject object) =>
+      $V.fromRef(_remove(reference, object.reference).object);
+
+  static final _clear = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(ffi.Pointer<ffi.Void>)>>("HashMap__clear")
+      .asFunction<jni.JniResult Function(ffi.Pointer<ffi.Void>)>();
+
+  /// from: public void clear()
+  void clear() => _clear(reference).check();
+
+  static final _containsValue = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>)>>("HashMap__containsValue")
+      .asFunction<
+          jni.JniResult Function(
+              ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>();
+
+  /// from: public boolean containsValue(java.lang.Object object)
+  bool containsValue(jni.JObject object) =>
+      _containsValue(reference, object.reference).boolean;
+
+  static final _keySet = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(ffi.Pointer<ffi.Void>)>>("HashMap__keySet")
+      .asFunction<jni.JniResult Function(ffi.Pointer<ffi.Void>)>();
+
+  /// from: public java.util.Set keySet()
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  jni.JObject keySet() =>
+      const jni.JObjectType().fromRef(_keySet(reference).object);
+
+  static final _values = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(ffi.Pointer<ffi.Void>)>>("HashMap__values")
+      .asFunction<jni.JniResult Function(ffi.Pointer<ffi.Void>)>();
+
+  /// from: public java.util.Collection values()
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  jni.JObject values() =>
+      const jni.JObjectType().fromRef(_values(reference).object);
+
+  static final _entrySet = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(
+                  ffi.Pointer<ffi.Void>)>>("HashMap__entrySet")
+      .asFunction<jni.JniResult Function(ffi.Pointer<ffi.Void>)>();
+
+  /// from: public java.util.Set entrySet()
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  jni.JObject entrySet() =>
+      const jni.JObjectType().fromRef(_entrySet(reference).object);
+
+  static final _getOrDefault = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>)>>("HashMap__getOrDefault")
+      .asFunction<
+          jni.JniResult Function(ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>,
+              ffi.Pointer<ffi.Void>)>();
+
+  /// from: public V getOrDefault(java.lang.Object object, V object1)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  V getOrDefault(jni.JObject object, V object1) => $V.fromRef(
+      _getOrDefault(reference, object.reference, object1.reference).object);
+
+  static final _putIfAbsent = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>)>>("HashMap__putIfAbsent")
+      .asFunction<
+          jni.JniResult Function(ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>,
+              ffi.Pointer<ffi.Void>)>();
+
+  /// from: public V putIfAbsent(K object, V object1)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  V putIfAbsent(K object, V object1) => $V.fromRef(
+      _putIfAbsent(reference, object.reference, object1.reference).object);
+
+  static final _remove1 = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>)>>("HashMap__remove1")
+      .asFunction<
+          jni.JniResult Function(ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>,
+              ffi.Pointer<ffi.Void>)>();
+
+  /// from: public boolean remove(java.lang.Object object, java.lang.Object object1)
+  bool remove1(jni.JObject object, jni.JObject object1) =>
+      _remove1(reference, object.reference, object1.reference).boolean;
+
+  static final _replace = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>)>>("HashMap__replace")
+      .asFunction<
+          jni.JniResult Function(ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>,
+              ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>();
+
+  /// from: public boolean replace(K object, V object1, V object2)
+  bool replace(K object, V object1, V object2) => _replace(
+          reference, object.reference, object1.reference, object2.reference)
+      .boolean;
+
+  static final _replace1 = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>)>>("HashMap__replace1")
+      .asFunction<
+          jni.JniResult Function(ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>,
+              ffi.Pointer<ffi.Void>)>();
+
+  /// from: public V replace(K object, V object1)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  V replace1(K object, V object1) => $V.fromRef(
+      _replace1(reference, object.reference, object1.reference).object);
+
+  static final _computeIfAbsent = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>)>>("HashMap__computeIfAbsent")
+      .asFunction<
+          jni.JniResult Function(ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>,
+              ffi.Pointer<ffi.Void>)>();
+
+  /// from: public V computeIfAbsent(K object, java.util.function.Function function)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  V computeIfAbsent(K object, jni.JObject function) => $V.fromRef(
+      _computeIfAbsent(reference, object.reference, function.reference).object);
+
+  static final _computeIfPresent = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>)>>("HashMap__computeIfPresent")
+      .asFunction<
+          jni.JniResult Function(ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>,
+              ffi.Pointer<ffi.Void>)>();
+
+  /// from: public V computeIfPresent(K object, java.util.function.BiFunction biFunction)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  V computeIfPresent(K object, jni.JObject biFunction) => $V.fromRef(
+      _computeIfPresent(reference, object.reference, biFunction.reference)
+          .object);
+
+  static final _compute = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>)>>("HashMap__compute")
+      .asFunction<
+          jni.JniResult Function(ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>,
+              ffi.Pointer<ffi.Void>)>();
+
+  /// from: public V compute(K object, java.util.function.BiFunction biFunction)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  V compute(K object, jni.JObject biFunction) => $V.fromRef(
+      _compute(reference, object.reference, biFunction.reference).object);
+
+  static final _merge = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>)>>("HashMap__merge")
+      .asFunction<
+          jni.JniResult Function(ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>,
+              ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>();
+
+  /// from: public V merge(K object, V object1, java.util.function.BiFunction biFunction)
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  V merge(K object, V object1, jni.JObject biFunction) => $V.fromRef(_merge(
+          reference, object.reference, object1.reference, biFunction.reference)
+      .object);
+
+  static final _forEach = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>)>>("HashMap__forEach")
+      .asFunction<
+          jni.JniResult Function(
+              ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>();
+
+  /// from: public void forEach(java.util.function.BiConsumer biConsumer)
+  void forEach(jni.JObject biConsumer) =>
+      _forEach(reference, biConsumer.reference).check();
+
+  static final _replaceAll = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(ffi.Pointer<ffi.Void>,
+                  ffi.Pointer<ffi.Void>)>>("HashMap__replaceAll")
+      .asFunction<
+          jni.JniResult Function(
+              ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>();
+
+  /// from: public void replaceAll(java.util.function.BiFunction biFunction)
+  void replaceAll(jni.JObject biFunction) =>
+      _replaceAll(reference, biFunction.reference).check();
+
+  static final _clone = jniLookup<
+          ffi.NativeFunction<
+              jni.JniResult Function(ffi.Pointer<ffi.Void>)>>("HashMap__clone")
+      .asFunction<jni.JniResult Function(ffi.Pointer<ffi.Void>)>();
+
+  /// from: public java.lang.Object clone()
+  /// The returned object must be deleted after use, by calling the `delete` method.
+  jni.JObject clone() =>
+      const jni.JObjectType().fromRef(_clone(reference).object);
+}
+
+class $HashMapType<K extends jni.JObject, V extends jni.JObject>
+    extends jni.JObjType<HashMap<K, V>> {
+  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);
+}
+
+extension $HashMapArray<K extends jni.JObject, V extends jni.JObject>
+    on jni.JArray<HashMap<K, V>> {
+  HashMap<K, V> operator [](int index) {
+    return (elementType as $HashMapType<K, V>)
+        .fromRef(elementAt(index, jni.JniCallType.objectType).object);
+  }
+
+  void operator []=(int index, HashMap<K, V> value) {
+    (this as jni.JArray<jni.JObject>)[index] = value;
+  }
+}
diff --git a/pkgs/jnigen/example/in_app_java/lib/main.dart b/pkgs/jnigen/example/in_app_java/lib/main.dart
index 901eb76..61c9d2b 100644
--- a/pkgs/jnigen/example/in_app_java/lib/main.dart
+++ b/pkgs/jnigen/example/in_app_java/lib/main.dart
@@ -11,9 +11,24 @@
 
 JObject activity = JObject.fromRef(Jni.getCurrentActivity());
 
-/// Display device model number as Toast
+final hashmap = HashMap.ctor2(JString.type, JString.type);
+
+extension IntX on int {
+  JString toJString() {
+    return toString().toJString();
+  }
+}
+
+/// Display device model number and the number of times this was called
+/// as Toast.
 void showToast() {
-  AndroidUtils.showToast(activity, Build.MODEL, 0);
+  final toastCount =
+      hashmap.getOrDefault("toastCount".toJString(), 0.toJString());
+  final newToastCount = (int.parse(toastCount.toDartString()) + 1).toJString();
+  hashmap.put("toastCount".toJString(), newToastCount);
+  final message =
+      '${newToastCount.toDartString()} - ${Build.MODEL.toDartString()}';
+  AndroidUtils.showToast(activity, message.toJString(), 0);
 }
 
 void main() {
diff --git a/pkgs/jnigen/example/in_app_java/src/android_utils/android_utils.c b/pkgs/jnigen/example/in_app_java/src/android_utils/android_utils.c
index b1e887a..1a1cb55 100644
--- a/pkgs/jnigen/example/in_app_java/src/android_utils/android_utils.c
+++ b/pkgs/jnigen/example/in_app_java/src/android_utils/android_utils.c
@@ -472,3 +472,472 @@
       (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__USER));
   return (JniResult){.result = {.l = _result}, .exception = check_exception()};
 }
+
+// java.util.HashMap
+jclass _c_HashMap = NULL;
+
+jmethodID _m_HashMap__ctor = NULL;
+FFI_PLUGIN_EXPORT
+JniResult HashMap__ctor(int32_t i, float f) {
+  load_env();
+  load_class_gr(&_c_HashMap, "java/util/HashMap");
+  if (_c_HashMap == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_HashMap, &_m_HashMap__ctor, "<init>", "(IF)V");
+  if (_m_HashMap__ctor == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result =
+      (*jniEnv)->NewObject(jniEnv, _c_HashMap, _m_HashMap__ctor, i, f);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_HashMap__ctor1 = NULL;
+FFI_PLUGIN_EXPORT
+JniResult HashMap__ctor1(int32_t i) {
+  load_env();
+  load_class_gr(&_c_HashMap, "java/util/HashMap");
+  if (_c_HashMap == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_HashMap, &_m_HashMap__ctor1, "<init>", "(I)V");
+  if (_m_HashMap__ctor1 == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result =
+      (*jniEnv)->NewObject(jniEnv, _c_HashMap, _m_HashMap__ctor1, i);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_HashMap__ctor2 = NULL;
+FFI_PLUGIN_EXPORT
+JniResult HashMap__ctor2() {
+  load_env();
+  load_class_gr(&_c_HashMap, "java/util/HashMap");
+  if (_c_HashMap == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_HashMap, &_m_HashMap__ctor2, "<init>", "()V");
+  if (_m_HashMap__ctor2 == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->NewObject(jniEnv, _c_HashMap, _m_HashMap__ctor2);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_HashMap__ctor3 = NULL;
+FFI_PLUGIN_EXPORT
+JniResult HashMap__ctor3(jobject map) {
+  load_env();
+  load_class_gr(&_c_HashMap, "java/util/HashMap");
+  if (_c_HashMap == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_HashMap, &_m_HashMap__ctor3, "<init>", "(Ljava/util/Map;)V");
+  if (_m_HashMap__ctor3 == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result =
+      (*jniEnv)->NewObject(jniEnv, _c_HashMap, _m_HashMap__ctor3, map);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_HashMap__size = NULL;
+FFI_PLUGIN_EXPORT
+JniResult HashMap__size(jobject self_) {
+  load_env();
+  load_class_gr(&_c_HashMap, "java/util/HashMap");
+  if (_c_HashMap == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_HashMap, &_m_HashMap__size, "size", "()I");
+  if (_m_HashMap__size == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  int32_t _result = (*jniEnv)->CallIntMethod(jniEnv, self_, _m_HashMap__size);
+  return (JniResult){.result = {.i = _result}, .exception = check_exception()};
+}
+
+jmethodID _m_HashMap__isEmpty = NULL;
+FFI_PLUGIN_EXPORT
+JniResult HashMap__isEmpty(jobject self_) {
+  load_env();
+  load_class_gr(&_c_HashMap, "java/util/HashMap");
+  if (_c_HashMap == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_HashMap, &_m_HashMap__isEmpty, "isEmpty", "()Z");
+  if (_m_HashMap__isEmpty == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  uint8_t _result =
+      (*jniEnv)->CallBooleanMethod(jniEnv, self_, _m_HashMap__isEmpty);
+  return (JniResult){.result = {.z = _result}, .exception = check_exception()};
+}
+
+jmethodID _m_HashMap__get0 = NULL;
+FFI_PLUGIN_EXPORT
+JniResult HashMap__get0(jobject self_, jobject object) {
+  load_env();
+  load_class_gr(&_c_HashMap, "java/util/HashMap");
+  if (_c_HashMap == NULL)
+    return (JniResult){.result = {.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){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result =
+      (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_HashMap__get0, object);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_HashMap__containsKey = NULL;
+FFI_PLUGIN_EXPORT
+JniResult HashMap__containsKey(jobject self_, jobject object) {
+  load_env();
+  load_class_gr(&_c_HashMap, "java/util/HashMap");
+  if (_c_HashMap == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_HashMap, &_m_HashMap__containsKey, "containsKey",
+              "(Ljava/lang/Object;)Z");
+  if (_m_HashMap__containsKey == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  uint8_t _result = (*jniEnv)->CallBooleanMethod(
+      jniEnv, self_, _m_HashMap__containsKey, object);
+  return (JniResult){.result = {.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_gr(&_c_HashMap, "java/util/HashMap");
+  if (_c_HashMap == NULL)
+    return (JniResult){.result = {.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){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_HashMap__put,
+                                                object, object1);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_HashMap__putAll = NULL;
+FFI_PLUGIN_EXPORT
+JniResult HashMap__putAll(jobject self_, jobject map) {
+  load_env();
+  load_class_gr(&_c_HashMap, "java/util/HashMap");
+  if (_c_HashMap == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_HashMap, &_m_HashMap__putAll, "putAll", "(Ljava/util/Map;)V");
+  if (_m_HashMap__putAll == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_HashMap__putAll, map);
+  return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+}
+
+jmethodID _m_HashMap__remove = NULL;
+FFI_PLUGIN_EXPORT
+JniResult HashMap__remove(jobject self_, jobject object) {
+  load_env();
+  load_class_gr(&_c_HashMap, "java/util/HashMap");
+  if (_c_HashMap == NULL)
+    return (JniResult){.result = {.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){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result =
+      (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_HashMap__remove, object);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_HashMap__clear = NULL;
+FFI_PLUGIN_EXPORT
+JniResult HashMap__clear(jobject self_) {
+  load_env();
+  load_class_gr(&_c_HashMap, "java/util/HashMap");
+  if (_c_HashMap == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_HashMap, &_m_HashMap__clear, "clear", "()V");
+  if (_m_HashMap__clear == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_HashMap__clear);
+  return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+}
+
+jmethodID _m_HashMap__containsValue = NULL;
+FFI_PLUGIN_EXPORT
+JniResult HashMap__containsValue(jobject self_, jobject object) {
+  load_env();
+  load_class_gr(&_c_HashMap, "java/util/HashMap");
+  if (_c_HashMap == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_HashMap, &_m_HashMap__containsValue, "containsValue",
+              "(Ljava/lang/Object;)Z");
+  if (_m_HashMap__containsValue == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  uint8_t _result = (*jniEnv)->CallBooleanMethod(
+      jniEnv, self_, _m_HashMap__containsValue, object);
+  return (JniResult){.result = {.z = _result}, .exception = check_exception()};
+}
+
+jmethodID _m_HashMap__keySet = NULL;
+FFI_PLUGIN_EXPORT
+JniResult HashMap__keySet(jobject self_) {
+  load_env();
+  load_class_gr(&_c_HashMap, "java/util/HashMap");
+  if (_c_HashMap == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_HashMap, &_m_HashMap__keySet, "keySet", "()Ljava/util/Set;");
+  if (_m_HashMap__keySet == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result =
+      (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_HashMap__keySet);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_HashMap__values = NULL;
+FFI_PLUGIN_EXPORT
+JniResult HashMap__values(jobject self_) {
+  load_env();
+  load_class_gr(&_c_HashMap, "java/util/HashMap");
+  if (_c_HashMap == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_HashMap, &_m_HashMap__values, "values",
+              "()Ljava/util/Collection;");
+  if (_m_HashMap__values == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result =
+      (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_HashMap__values);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_HashMap__entrySet = NULL;
+FFI_PLUGIN_EXPORT
+JniResult HashMap__entrySet(jobject self_) {
+  load_env();
+  load_class_gr(&_c_HashMap, "java/util/HashMap");
+  if (_c_HashMap == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_HashMap, &_m_HashMap__entrySet, "entrySet",
+              "()Ljava/util/Set;");
+  if (_m_HashMap__entrySet == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result =
+      (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_HashMap__entrySet);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_HashMap__getOrDefault = NULL;
+FFI_PLUGIN_EXPORT
+JniResult HashMap__getOrDefault(jobject self_,
+                                jobject object,
+                                jobject object1) {
+  load_env();
+  load_class_gr(&_c_HashMap, "java/util/HashMap");
+  if (_c_HashMap == NULL)
+    return (JniResult){.result = {.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){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallObjectMethod(
+      jniEnv, self_, _m_HashMap__getOrDefault, object, object1);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_HashMap__putIfAbsent = NULL;
+FFI_PLUGIN_EXPORT
+JniResult HashMap__putIfAbsent(jobject self_, jobject object, jobject object1) {
+  load_env();
+  load_class_gr(&_c_HashMap, "java/util/HashMap");
+  if (_c_HashMap == NULL)
+    return (JniResult){.result = {.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){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallObjectMethod(
+      jniEnv, self_, _m_HashMap__putIfAbsent, object, object1);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_HashMap__remove1 = NULL;
+FFI_PLUGIN_EXPORT
+JniResult HashMap__remove1(jobject self_, jobject object, jobject object1) {
+  load_env();
+  load_class_gr(&_c_HashMap, "java/util/HashMap");
+  if (_c_HashMap == NULL)
+    return (JniResult){.result = {.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){.result = {.j = 0}, .exception = check_exception()};
+  uint8_t _result = (*jniEnv)->CallBooleanMethod(
+      jniEnv, self_, _m_HashMap__remove1, object, object1);
+  return (JniResult){.result = {.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_gr(&_c_HashMap, "java/util/HashMap");
+  if (_c_HashMap == NULL)
+    return (JniResult){.result = {.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){.result = {.j = 0}, .exception = check_exception()};
+  uint8_t _result = (*jniEnv)->CallBooleanMethod(
+      jniEnv, self_, _m_HashMap__replace, object, object1, object2);
+  return (JniResult){.result = {.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_gr(&_c_HashMap, "java/util/HashMap");
+  if (_c_HashMap == NULL)
+    return (JniResult){.result = {.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){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallObjectMethod(
+      jniEnv, self_, _m_HashMap__replace1, object, object1);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_HashMap__computeIfAbsent = NULL;
+FFI_PLUGIN_EXPORT
+JniResult HashMap__computeIfAbsent(jobject self_,
+                                   jobject object,
+                                   jobject function) {
+  load_env();
+  load_class_gr(&_c_HashMap, "java/util/HashMap");
+  if (_c_HashMap == NULL)
+    return (JniResult){.result = {.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){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallObjectMethod(
+      jniEnv, self_, _m_HashMap__computeIfAbsent, object, function);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_HashMap__computeIfPresent = NULL;
+FFI_PLUGIN_EXPORT
+JniResult HashMap__computeIfPresent(jobject self_,
+                                    jobject object,
+                                    jobject biFunction) {
+  load_env();
+  load_class_gr(&_c_HashMap, "java/util/HashMap");
+  if (_c_HashMap == NULL)
+    return (JniResult){.result = {.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){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallObjectMethod(
+      jniEnv, self_, _m_HashMap__computeIfPresent, object, biFunction);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_HashMap__compute = NULL;
+FFI_PLUGIN_EXPORT
+JniResult HashMap__compute(jobject self_, jobject object, jobject biFunction) {
+  load_env();
+  load_class_gr(&_c_HashMap, "java/util/HashMap");
+  if (_c_HashMap == NULL)
+    return (JniResult){.result = {.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){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallObjectMethod(
+      jniEnv, self_, _m_HashMap__compute, object, biFunction);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_HashMap__merge = NULL;
+FFI_PLUGIN_EXPORT
+JniResult HashMap__merge(jobject self_,
+                         jobject object,
+                         jobject object1,
+                         jobject biFunction) {
+  load_env();
+  load_class_gr(&_c_HashMap, "java/util/HashMap");
+  if (_c_HashMap == NULL)
+    return (JniResult){.result = {.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){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result = (*jniEnv)->CallObjectMethod(
+      jniEnv, self_, _m_HashMap__merge, object, object1, biFunction);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
+
+jmethodID _m_HashMap__forEach = NULL;
+FFI_PLUGIN_EXPORT
+JniResult HashMap__forEach(jobject self_, jobject biConsumer) {
+  load_env();
+  load_class_gr(&_c_HashMap, "java/util/HashMap");
+  if (_c_HashMap == NULL)
+    return (JniResult){.result = {.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){.result = {.j = 0}, .exception = check_exception()};
+  (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_HashMap__forEach, biConsumer);
+  return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+}
+
+jmethodID _m_HashMap__replaceAll = NULL;
+FFI_PLUGIN_EXPORT
+JniResult HashMap__replaceAll(jobject self_, jobject biFunction) {
+  load_env();
+  load_class_gr(&_c_HashMap, "java/util/HashMap");
+  if (_c_HashMap == NULL)
+    return (JniResult){.result = {.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){.result = {.j = 0}, .exception = check_exception()};
+  (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_HashMap__replaceAll, biFunction);
+  return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+}
+
+jmethodID _m_HashMap__clone = NULL;
+FFI_PLUGIN_EXPORT
+JniResult HashMap__clone(jobject self_) {
+  load_env();
+  load_class_gr(&_c_HashMap, "java/util/HashMap");
+  if (_c_HashMap == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  load_method(_c_HashMap, &_m_HashMap__clone, "clone", "()Ljava/lang/Object;");
+  if (_m_HashMap__clone == NULL)
+    return (JniResult){.result = {.j = 0}, .exception = check_exception()};
+  jobject _result =
+      (*jniEnv)->CallObjectMethod(jniEnv, self_, _m_HashMap__clone);
+  return (JniResult){.result = {.l = to_global_ref(_result)},
+                     .exception = check_exception()};
+}
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
index 4f9512e..f32c119 100644
--- 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
@@ -484,7 +484,7 @@
   ///@return a <code>List</code> of <code>PDSignatureField</code>s
   ///@throws IOException if no document catalog can be found.
   jni.JObject getSignatureFields() =>
-      jni.JObjectType().fromRef(_getSignatureFields(reference).object);
+      const jni.JObjectType().fromRef(_getSignatureFields(reference).object);
 
   static final _getSignatureDictionaries = jniLookup<
               ffi.NativeFunction<
@@ -498,8 +498,8 @@
   /// Retrieve all signature dictionaries from the document.
   ///@return a <code>List</code> of <code>PDSignatureField</code>s
   ///@throws IOException if no document catalog can be found.
-  jni.JObject getSignatureDictionaries() =>
-      jni.JObjectType().fromRef(_getSignatureDictionaries(reference).object);
+  jni.JObject getSignatureDictionaries() => const jni.JObjectType()
+      .fromRef(_getSignatureDictionaries(reference).object);
 
   static final _registerTrueTypeFontForClosing = jniLookup<
               ffi.NativeFunction<
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
index f152767..46928c0 100644
--- 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
@@ -377,7 +377,7 @@
   ///@return all metadata key strings.
   ///@since Apache PDFBox 1.3.0
   jni.JObject getMetadataKeys() =>
-      jni.JObjectType().fromRef(_getMetadataKeys(reference).object);
+      const jni.JObjectType().fromRef(_getMetadataKeys(reference).object);
 
   static final _getCustomMetadataValue = jniLookup<
               ffi.NativeFunction<
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
index 45eea01..e442778 100644
--- 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
@@ -100,8 +100,8 @@
   /// text after second article
   ///
   /// Most PDFs won't have any beads, so charactersByArticle will contain a single entry.
-  jni.JObject get charactersByArticle =>
-      jni.JObjectType().fromRef(_get_charactersByArticle(reference).object);
+  jni.JObject get charactersByArticle => const jni.JObjectType()
+      .fromRef(_get_charactersByArticle(reference).object);
   static final _set_charactersByArticle = jniLookup<
               ffi.NativeFunction<
                   jni.JThrowablePtr Function(
@@ -642,8 +642,8 @@
   /// 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.JObject getCharactersByArticle() =>
-      jni.JObjectType().fromRef(_getCharactersByArticle(reference).object);
+  jni.JObject getCharactersByArticle() => const jni.JObjectType()
+      .fromRef(_getCharactersByArticle(reference).object);
 
   static final _setSuppressDuplicateOverlappingText = jniLookup<
               ffi.NativeFunction<
@@ -1191,7 +1191,7 @@
   /// This method returns a list of such regular expression Patterns.
   ///@return a list of Pattern objects.
   jni.JObject getListItemPatterns() =>
-      jni.JObjectType().fromRef(_getListItemPatterns(reference).object);
+      const jni.JObjectType().fromRef(_getListItemPatterns(reference).object);
 
   static final _matchPattern = jniLookup<
           ffi.NativeFunction<
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 0000000..8805c7f
--- /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
index c822342..f542fe8 100644
--- 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
@@ -12,6 +12,7 @@
 import com.github.dart_lang.jnigen.apisummarizer.util.StreamUtil;
 import java.util.*;
 import org.objectweb.asm.*;
+import org.objectweb.asm.signature.SignatureReader;
 
 public class AsmClassVisitor extends ClassVisitor implements AsmAnnotatedElementVisitor {
   private static Param param(
@@ -53,6 +54,10 @@
     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);
   }
 
@@ -66,11 +71,16 @@
     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 (signature != null) {
+      var reader = new SignatureReader(signature);
+      reader.accept(new AsmTypeUsageSignatureVisitor(field.type));
+    }
     peekVisiting().fields.add(field);
     return new AsmFieldVisitor(field);
   }
@@ -101,6 +111,10 @@
     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);
   }
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 0000000..9067f9e
--- /dev/null
+++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/AsmMethodSignatureVisitor.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.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 org.objectweb.asm.signature.SignatureVisitor;
+
+public class AsmMethodSignatureVisitor extends SignatureVisitor {
+  private final Method method;
+  private int paramIndex = -1;
+
+  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() {
+    return new AsmTypeUsageSignatureVisitor(method.returnType);
+  }
+
+  @Override
+  public SignatureVisitor visitParameterType() {
+    paramIndex++;
+    return new AsmTypeUsageSignatureVisitor(method.params.get(paramIndex).type);
+  }
+
+  @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/AsmTypeUsageSignatureVisitor.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/AsmTypeUsageSignatureVisitor.java
new file mode 100644
index 0000000..dc0f5a4
--- /dev/null
+++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/AsmTypeUsageSignatureVisitor.java
@@ -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.
+
+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(name, 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) {
+    super.visitInnerClassType(name);
+    // TODO(#139) support nested generic classes
+  }
+}
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
index 8131a55..42e069e 100644
--- 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
@@ -32,11 +32,11 @@
 
   public String parentName;
   public String packageName;
-  public List<TypeParam> typeParams;
+  public List<TypeParam> typeParams = new ArrayList<>();
   public List<Method> methods = new ArrayList<>();
   public List<Field> fields = new ArrayList<>();
   public TypeUsage superclass;
-  public List<TypeUsage> interfaces;
+  public List<TypeUsage> interfaces = new ArrayList<>();
   public boolean hasStaticInit;
   public boolean hasInstanceInit;
   public JavaDocComment javadoc;
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
index bb558f4..0711c10 100644
--- 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
@@ -12,7 +12,7 @@
 public class Method {
   public Set<String> modifiers = new HashSet<>();
   public String name;
-  public List<TypeParam> typeParams;
+  public List<TypeParam> typeParams = new ArrayList<>();
   public List<Param> params = new ArrayList<>();
   public TypeUsage returnType;
 
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
index 9045578..8172ee6 100644
--- 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
@@ -4,9 +4,10 @@
 
 package com.github.dart_lang.jnigen.apisummarizer.elements;
 
+import java.util.ArrayList;
 import java.util.List;
 
 public class TypeParam {
   public String name;
-  public List<TypeUsage> bounds;
+  public List<TypeUsage> bounds = new ArrayList<>();
 }
diff --git a/pkgs/jnigen/lib/src/bindings/common.dart b/pkgs/jnigen/lib/src/bindings/common.dart
index 5c5a2c8..19fba11 100644
--- a/pkgs/jnigen/lib/src/bindings/common.dart
+++ b/pkgs/jnigen/lib/src/bindings/common.dart
@@ -320,15 +320,16 @@
         if (resolver != null) {
           final type = t.type as DeclaredType;
           final resolved = resolver.resolve(type.binaryName);
-          if (resolved == null) {
+          final resolvedClass = resolver.resolveClass(type.binaryName);
+          if (resolved == null ||
+              resolvedClass == null ||
+              !resolvedClass.isIncluded) {
             return jniObjectType;
           }
 
           // All type parameters of this type
           final allTypeParams =
-              (resolver.resolveClass(type.binaryName)?.allTypeParams ?? [])
-                  .map((param) => param.name)
-                  .toList();
+              resolvedClass.allTypeParams.map((param) => param.name).toList();
 
           // The ones that are declared.
           final paramTypeClasses =
@@ -405,11 +406,19 @@
         final resolved = resolver.resolve(type.binaryName);
         final resolvedClass = resolver.resolveClass(type.binaryName);
 
+        if (resolved == null ||
+            resolvedClass == null ||
+            !resolvedClass.isIncluded) {
+          return _TypeClass(
+            '${addConst ? 'const ' : ''}$jniObjectTypeClass()',
+            true,
+          );
+        }
+
         // All type params of this type
-        final allTypeParams = resolvedClass?.allTypeParams
-                .map((param) => '$typeParamPrefix${param.name}')
-                .toList() ??
-            [];
+        final allTypeParams = resolvedClass.allTypeParams
+            .map((param) => '$typeParamPrefix${param.name}')
+            .toList();
 
         // The ones that are declared.
         final paramTypeClasses = type.params.map(
@@ -426,11 +435,12 @@
 
         final args = allTypeParams.join(',');
 
-        final canBeConst = allTypeParams.length == paramTypeClasses.length &&
-            paramTypeClasses.every((e) => e.canBeConst);
+        final canBeConst = (allTypeParams.length == paramTypeClasses.length &&
+                paramTypeClasses.every((e) => e.canBeConst)) ||
+            allTypeParams.isEmpty;
         final ifConst = addConst && canBeConst ? 'const ' : '';
 
-        if (resolved == null || resolved == jniObjectType) {
+        if (resolved == jniObjectType) {
           return _TypeClass('$ifConst$jniObjectTypeClass()', true);
         } else if (resolved == jniStringType) {
           return _TypeClass('$ifConst$jniStringTypeClass()', true);
diff --git a/pkgs/jnigen/lib/src/writers/files_writer.dart b/pkgs/jnigen/lib/src/writers/files_writer.dart
index 9e78ea3..7361915 100644
--- a/pkgs/jnigen/lib/src/writers/files_writer.dart
+++ b/pkgs/jnigen/lib/src/writers/files_writer.dart
@@ -34,6 +34,16 @@
     'java.lang.String': 'jni.JString',
   };
 
+  static final predefinedClasses = {
+    'java.lang.String': ClassDecl(
+      binaryName: 'java.lang.String',
+      packageName: 'java.lang',
+      simpleName: 'String',
+    )
+      ..isIncluded = true
+      ..isPreprocessed = true,
+  };
+
   /// A map of all classes by their names
   final Map<String, ClassDecl> classes;
 
@@ -165,6 +175,9 @@
 
   @override
   ClassDecl? resolveClass(String binaryName) {
+    if (predefinedClasses.containsKey(binaryName)) {
+      return predefinedClasses[binaryName];
+    }
     return classes[binaryName];
   }
 }
diff --git a/pkgs/jnigen/lib/src/writers/single_file_writer.dart b/pkgs/jnigen/lib/src/writers/single_file_writer.dart
index ee6875f..8d8e5c7 100644
--- a/pkgs/jnigen/lib/src/writers/single_file_writer.dart
+++ b/pkgs/jnigen/lib/src/writers/single_file_writer.dart
@@ -14,6 +14,15 @@
   static const predefined = {
     'java.lang.String': 'jni.JString',
   };
+  static final predefinedClasses = {
+    'java.lang.String': ClassDecl(
+      binaryName: 'java.lang.String',
+      packageName: 'java.lang',
+      simpleName: 'String',
+    )
+      ..isIncluded = true
+      ..isPreprocessed = true,
+  };
   Map<String, ClassDecl> inputClasses;
   SingleFileResolver(this.inputClasses);
   @override
@@ -29,6 +38,9 @@
 
   @override
   ClassDecl? resolveClass(String binaryName) {
+    if (predefinedClasses.containsKey(binaryName)) {
+      return predefinedClasses[binaryName];
+    }
     return inputClasses[binaryName];
   }
 }
diff --git a/pkgs/jnigen/test/jackson_core_test/generate.dart b/pkgs/jnigen/test/jackson_core_test/generate.dart
index 37749d5..c804e57 100644
--- a/pkgs/jnigen/test/jackson_core_test/generate.dart
+++ b/pkgs/jnigen/test/jackson_core_test/generate.dart
@@ -56,13 +56,17 @@
           ],
     logLevel: Level.INFO,
     exclude: BindingExclusions(
-      fields: excludeAll<Field>([
-        ['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(#31): Remove field exclusions.
+        fields: excludeAll<Field>([
+          ['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',
+        )),
   );
   return config;
 }
diff --git a/pkgs/jnigen/test/jackson_core_test/third_party/lib/com/fasterxml/jackson/core/JsonFactory.dart b/pkgs/jnigen/test/jackson_core_test/third_party/lib/com/fasterxml/jackson/core/JsonFactory.dart
index 32377ce..be5fc9f 100644
--- a/pkgs/jnigen/test/jackson_core_test/third_party/lib/com/fasterxml/jackson/core/JsonFactory.dart
+++ b/pkgs/jnigen/test/jackson_core_test/third_party/lib/com/fasterxml/jackson/core/JsonFactory.dart
@@ -205,7 +205,7 @@
   ///@return Builder instance to use
   ///@since 2.10
   jni.JObject rebuild() =>
-      jni.JObjectType().fromRef(jniAccessors.callMethodWithArgs(
+      const jni.JObjectType().fromRef(jniAccessors.callMethodWithArgs(
           reference, _id_rebuild, jni.JniCallType.objectType, []).object);
 
   static final _id_builder = jniAccessors.getStaticMethodIDOf(
@@ -223,7 +223,7 @@
   /// will be fixed in 3.0.
   ///@return Builder instance to use
   static jni.JObject builder() =>
-      jni.JObjectType().fromRef(jniAccessors.callStaticMethodWithArgs(
+      const jni.JObjectType().fromRef(jniAccessors.callStaticMethodWithArgs(
           _classRef, _id_builder, jni.JniCallType.objectType, []).object);
 
   static final _id_copy = jniAccessors.getMethodIDOf(
@@ -345,7 +345,7 @@
   /// from: public java.lang.Class<? extends com.fasterxml.jackson.core.FormatFeature> getFormatReadFeatureType()
   /// The returned object must be deleted after use, by calling the `delete` method.
   jni.JObject getFormatReadFeatureType() =>
-      jni.JObjectType().fromRef(jniAccessors.callMethodWithArgs(reference,
+      const jni.JObjectType().fromRef(jniAccessors.callMethodWithArgs(reference,
           _id_getFormatReadFeatureType, jni.JniCallType.objectType, []).object);
 
   static final _id_getFormatWriteFeatureType = jniAccessors.getMethodIDOf(
@@ -354,7 +354,7 @@
   /// from: public java.lang.Class<? extends com.fasterxml.jackson.core.FormatFeature> getFormatWriteFeatureType()
   /// The returned object must be deleted after use, by calling the `delete` method.
   jni.JObject getFormatWriteFeatureType() =>
-      jni.JObjectType().fromRef(jniAccessors.callMethodWithArgs(
+      const jni.JObjectType().fromRef(jniAccessors.callMethodWithArgs(
           reference,
           _id_getFormatWriteFeatureType,
           jni.JniCallType.objectType, []).object);
diff --git a/pkgs/jnigen/test/jackson_core_test/third_party/lib/com/fasterxml/jackson/core/JsonParser.dart b/pkgs/jnigen/test/jackson_core_test/third_party/lib/com/fasterxml/jackson/core/JsonParser.dart
index 4d049fb..2e1305e 100644
--- a/pkgs/jnigen/test/jackson_core_test/third_party/lib/com/fasterxml/jackson/core/JsonParser.dart
+++ b/pkgs/jnigen/test/jackson_core_test/third_party/lib/com/fasterxml/jackson/core/JsonParser.dart
@@ -72,7 +72,7 @@
   /// set needs to be passed).
   ///@since 2.12
   static jni.JObject get DEFAULT_READ_CAPABILITIES =>
-      jni.JObjectType().fromRef(jniAccessors
+      const jni.JObjectType().fromRef(jniAccessors
           .getStaticField(_classRef, _id_DEFAULT_READ_CAPABILITIES,
               jni.JniCallType.objectType)
           .object);
@@ -305,7 +305,7 @@
   ///@return Set of read capabilities for content to read via this parser
   ///@since 2.12
   jni.JObject getReadCapabilities() =>
-      jni.JObjectType().fromRef(jniAccessors.callMethodWithArgs(reference,
+      const jni.JObjectType().fromRef(jniAccessors.callMethodWithArgs(reference,
           _id_getReadCapabilities, jni.JniCallType.objectType, []).object);
 
   static final _id_version = jniAccessors.getMethodIDOf(
@@ -2144,7 +2144,7 @@
   ///    issue at format layer
   jni.JObject readValuesAs<T extends jni.JObject>(
           jni.JObjType<T> $T, jni.JObject valueType) =>
-      jni.JObjectType().fromRef(jniAccessors.callMethodWithArgs(
+      const jni.JObjectType().fromRef(jniAccessors.callMethodWithArgs(
           reference,
           _id_readValuesAs,
           jni.JniCallType.objectType,
@@ -2168,7 +2168,7 @@
   ///    issue at format layer
   jni.JObject readValuesAs1<T extends jni.JObject>(
           jni.JObjType<T> $T, jni.JObject valueTypeRef) =>
-      jni.JObjectType().fromRef(jniAccessors.callMethodWithArgs(
+      const jni.JObjectType().fromRef(jniAccessors.callMethodWithArgs(
           reference,
           _id_readValuesAs1,
           jni.JniCallType.objectType,
diff --git a/pkgs/jnigen/test/simple_package_test/generate.dart b/pkgs/jnigen/test/simple_package_test/generate.dart
index 657dd90..962fe17 100644
--- a/pkgs/jnigen/test/simple_package_test/generate.dart
+++ b/pkgs/jnigen/test/simple_package_test/generate.dart
@@ -39,7 +39,7 @@
   final procRes = Process.runSync('javac', files, workingDirectory: workingDir);
   if (procRes.exitCode != 0) {
     throw "javac exited with ${procRes.exitCode}\n"
-        "$procRes.stderr";
+        "${procRes.stderr}";
   }
 }
 
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
index 0f025b8..c005ae0 100644
--- 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
@@ -1,3 +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<K> extends MyMap<K, String> {}