From 0cea9285f6b11c51af4017c576eb619a172fffec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yusuf=20=C4=B0hsan=20G=C3=B6rgel?= Date: Sun, 2 Aug 2026 23:42:29 +0300 Subject: [PATCH 1/2] [jnigen] Report empty class entries in Input --- pkgs/jnigen/lib/src/config/config_types.dart | 9 ++++-- pkgs/jnigen/test/config_test.dart | 33 ++++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/pkgs/jnigen/lib/src/config/config_types.dart b/pkgs/jnigen/lib/src/config/config_types.dart index 1aaf21c8ac..819ec5d8e2 100644 --- a/pkgs/jnigen/lib/src/config/config_types.dart +++ b/pkgs/jnigen/lib/src/config/config_types.dart @@ -344,8 +344,13 @@ final class Input { this.androidSdk, this.summarizerCommand, }) : workingDirectory = workingDirectory ?? Uri.directory('.') { - for (final className in classes) { - _validateClassName(className); + final entries = classes.cast(); + for (var i = 0; i < entries.length; i++) { + final className = entries[i]; + if (className == null) { + throw ConfigException('Entry ${i + 1} of "classes" is empty.'); + } + _validateClassName(className as String); } } } diff --git a/pkgs/jnigen/test/config_test.dart b/pkgs/jnigen/test/config_test.dart index 2e9ad8d8d0..8b7dc33ea7 100644 --- a/pkgs/jnigen/test/config_test.dart +++ b/pkgs/jnigen/test/config_test.dart @@ -118,5 +118,38 @@ void main() async { name: 'Nested class specified', overrides: ['-Dclasses=com.android.Clock\$Clock'], ); + + test('Empty classes entry from YAML', () { + final dir = Directory.systemTemp.createTempSync('jnigen_config_test'); + addTearDown(() => dir.deleteSync(recursive: true)); + final yaml = File(join(dir.path, 'jnigen.yaml'))..writeAsStringSync(''' +output: + dart: + path: lib/gen.dart + structure: single_file +classes: + - "com.example.Foo" + - +'''); + expect( + () => JniGenerator.parseArgs(['--config', yaml.path]), + throwsA(isA().having( + (error) => error.message, + 'message', + 'Entry 2 of "classes" is empty.', + )), + ); + }); + + test('Empty classes entry from Dart API', () { + expect( + () => Input(classes: ['com.example.Foo', null].cast()), + throwsA(isA().having( + (error) => error.message, + 'message', + 'Entry 2 of "classes" is empty.', + )), + ); + }); }); } From 37ad0ba29715433e915009c616cb4fedc5c5f6ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yusuf=20=C4=B0hsan=20G=C3=B6rgel?= Date: Fri, 11 Sep 2026 11:34:06 +0300 Subject: [PATCH 2/2] [jnigen] Reject an empty class name from the config --- pkgs/jnigen/CHANGELOG.md | 2 ++ pkgs/jnigen/lib/src/config/config_types.dart | 19 +++++++++++-------- pkgs/jnigen/test/config_test.dart | 13 +------------ 3 files changed, 14 insertions(+), 20 deletions(-) diff --git a/pkgs/jnigen/CHANGELOG.md b/pkgs/jnigen/CHANGELOG.md index d46b08f970..0ae7dd5293 100644 --- a/pkgs/jnigen/CHANGELOG.md +++ b/pkgs/jnigen/CHANGELOG.md @@ -1,5 +1,7 @@ ## 1.0.1-wip +- Report an empty entry under `classes` in the config file as a config error + instead of failing with a type error. - Generate links to method-specific Javadocs for Maven dependencies when source Javadocs are unavailable. diff --git a/pkgs/jnigen/lib/src/config/config_types.dart b/pkgs/jnigen/lib/src/config/config_types.dart index 819ec5d8e2..1b5061d2dd 100644 --- a/pkgs/jnigen/lib/src/config/config_types.dart +++ b/pkgs/jnigen/lib/src/config/config_types.dart @@ -344,13 +344,8 @@ final class Input { this.androidSdk, this.summarizerCommand, }) : workingDirectory = workingDirectory ?? Uri.directory('.') { - final entries = classes.cast(); - for (var i = 0; i < entries.length; i++) { - final className = entries[i]; - if (className == null) { - throw ConfigException('Entry ${i + 1} of "classes" is empty.'); - } - _validateClassName(className as String); + for (final className in classes) { + _validateClassName(className); } } } @@ -361,6 +356,9 @@ bool _isCapitalized(String s) { } void _validateClassName(String className) { + if (className.isEmpty) { + throw ConfigException('Class names cannot be empty.'); + } final parts = className.split('.'); assert(parts.isNotEmpty); const nestedClassesInfo = @@ -476,7 +474,12 @@ final class JniGenerator { input: Input( sourcePath: prov.getPathList(_Props.sourcePath) ?? const [], classPath: prov.getPathList(_Props.classPath) ?? const [], - classes: must(prov.getStringList, [], _Props.classes), + classes: must(prov.getStringList, [], _Props.classes) + // An empty YAML entry reads as null. Turn it into an empty name so + // that _validateClassName reports it instead of a cast error. + .cast() + .map((className) => className as String? ?? '') + .toList(), extraArgs: prov.getStringList(_Props.summarizerArgs) ?? const [], backend: getSummarizerBackend(prov.getString(_Props.backend), null), workingDirectory: prov.getPath(_Props.summarizerWorkingDir), diff --git a/pkgs/jnigen/test/config_test.dart b/pkgs/jnigen/test/config_test.dart index 8b7dc33ea7..18b4c136a1 100644 --- a/pkgs/jnigen/test/config_test.dart +++ b/pkgs/jnigen/test/config_test.dart @@ -136,18 +136,7 @@ classes: throwsA(isA().having( (error) => error.message, 'message', - 'Entry 2 of "classes" is empty.', - )), - ); - }); - - test('Empty classes entry from Dart API', () { - expect( - () => Input(classes: ['com.example.Foo', null].cast()), - throwsA(isA().having( - (error) => error.message, - 'message', - 'Entry 2 of "classes" is empty.', + 'Class names cannot be empty.', )), ); });