diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md
index 84883aa08..29c3bc02e 100644
--- a/RELEASE-NOTES.md
+++ b/RELEASE-NOTES.md
@@ -22,17 +22,17 @@ Artifacts in this release are signed by Remko Popma (6601 E5C0 8DCC BB96).
`PropertiesDefaultProvider` now tries to load properties from the classpath if the file cannot be found in the user.home directory.
-
## Fixed issues
* [#2102][#2107] Enhancement: `PropertiesDefaultProvider` should try to load properties from classpath (last). Thanks to [Lumír Návrat](https://github.com/rimuln) for the pull request.
* [#2202] Enhancement: Change log level from WARN to INFO when bean not found in ApplicationContext. Thanks to [Desmond Kirrane](https://github.com/dkirrane) for raising this.
* [#2248] Enhancement: Don't show hidden commands in JLine3 command description. Thanks to [Reinhard Handler](https://github.com/rehand) for the pull request.
+* [#2170] Enhancement: Use `...` vararg instead of array parameter to match overridden method signature. Thanks to [Michael Vorburger](https://github.com/vorburger) for the pull request.
* [#2058] Bugfix: `defaultValue` should not be applied in addition to user-specified value for options with a custom `IParameterConsumer`. Thanks to [Staffan Arvidsson McShane](https://github.com/StaffanArvidsson) for raising this.
* [#2148] Bugfix: Fix NPE in jline3 `Example.jar` as `ConfigurationPath` cannot be `null` anymore. Thanks to [llzen44](https://github.com/llzen44) for the pull request.
* [#2232] Bugfix: fix bug for `Optional` arguments with initial value. Thanks to [hq6](https://github.com/hq6) for raising this.
* [#2149] Bugfix: `@Option`-annotated setter method not invoked with default value when used in mixin for both command and subcommand. Thanks to [Zhonghao Wang](https://github.com/JBWKZsf) for raising this.
-* [#2170] Enhancement: Use `...` vararg instead of array parameter to match overridden method signature. Thanks to [Michael Vorburger](https://github.com/vorburger) for the pull request.
+* [#2270] Bugfix: Custom type converter for primitive `boolean` options should not be ignored. Thanks to [Sven Kammerer](https://codeberg.org/sven.k) for raising this.
* [#2234] BUILD: fix errorprone `TruthSelfEquals` warnings
* [#2172] BUILD: Fix broken build. Thanks to [Michael Vorburger](https://github.com/vorburger) for the pull request.
* [#2174] BUILD: Fix .gitattributes related CR/LF problems. Thanks to [Michael Vorburger](https://github.com/vorburger) for the pull request.
diff --git a/picocli-tests-java8/build.gradle b/picocli-tests-java8/build.gradle
index 123e5d83c..565d5eb7f 100644
--- a/picocli-tests-java8/build.gradle
+++ b/picocli-tests-java8/build.gradle
@@ -16,9 +16,8 @@ test {
dependencies {
api rootProject
- testImplementation supportDependencies.junit5Api
- testRuntimeOnly supportDependencies.junit5Engine
- testImplementation supportDependencies.systemLambda
+ testImplementation supportDependencies.junit
+ testImplementation supportDependencies.hamcrestCore
}
jar {
diff --git a/picocli-tests-java8/src/test/java/picocli/Issue2270.java b/picocli-tests-java8/src/test/java/picocli/Issue2270.java
new file mode 100644
index 000000000..5d087330f
--- /dev/null
+++ b/picocli-tests-java8/src/test/java/picocli/Issue2270.java
@@ -0,0 +1,78 @@
+package picocli;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import picocli.CommandLine.ITypeConverter;
+import picocli.CommandLine.Option;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.List;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+import static org.junit.Assert.*;
+
+public class Issue2270 {
+ static class CmdObjectBoolean {
+ @Option(names = "--test-Boolean", defaultValue = "dHJ1ZQ==" /* base64-encoded 'true' */)
+ Boolean testBoolean;
+ }
+ static class CmdPrimitiveBoolean {
+ @Option(names = "--test-boolean", defaultValue = "dHJ1ZQ==" /* base64-encoded 'true' */)
+ boolean testboolean;
+ }
+
+ static class Base64BooleanTypeConverter implements ITypeConverter {
+
+ static List invocations = new ArrayList<>();
+
+ public Boolean convert(String value) {
+ invocations.add(value);
+ System.out.printf("converter invocation %s: called with value %s%n",
+ invocations.size(), value);
+ if (Boolean.parseBoolean(value)) {
+ return true;
+ }
+ return Boolean.parseBoolean(new String(Base64.getDecoder().decode(value)));
+ }
+ }
+
+ @Before
+ public void beforeTests() {
+ CommandLine.tracer().setLevel(CommandLine.TraceLevel.DEBUG);
+ }
+
+ @After
+ public void afterTests() {
+ CommandLine.tracer().setLevel(CommandLine.TraceLevel.WARN);
+ }
+
+ @Test
+ public void testObjectBoolean() {
+ Base64BooleanTypeConverter.invocations.clear();
+ CmdObjectBoolean cmd = new CmdObjectBoolean();
+ new CommandLine(cmd)
+ .registerConverter(Boolean.class, new Base64BooleanTypeConverter())
+ .parseArgs();
+ assertThat(Base64BooleanTypeConverter.invocations.size(), greaterThanOrEqualTo(1));
+ assertEquals(Arrays.asList("dHJ1ZQ==", "true"), Base64BooleanTypeConverter.invocations);
+
+ assertTrue(cmd.testBoolean);
+ }
+
+ @Test
+ public void testPrimitiveBoolean() {
+ Base64BooleanTypeConverter.invocations.clear();
+ CmdPrimitiveBoolean cmd = new CmdPrimitiveBoolean();
+ new CommandLine(cmd)
+ .registerConverter(Boolean.TYPE, new Base64BooleanTypeConverter())
+ .parseArgs();
+ assertThat(Base64BooleanTypeConverter.invocations.size(), greaterThanOrEqualTo(1));
+ assertEquals(Arrays.asList("dHJ1ZQ==", "true"), Base64BooleanTypeConverter.invocations);
+
+ assertTrue(cmd.testboolean);
+ }
+}
diff --git a/src/main/java/picocli/CommandLine.java b/src/main/java/picocli/CommandLine.java
index 46953013a..d1910f0d5 100644
--- a/src/main/java/picocli/CommandLine.java
+++ b/src/main/java/picocli/CommandLine.java
@@ -14910,7 +14910,7 @@ private boolean booleanValue(ArgSpec argSpec, Object value) {
}
String stringValue = String.valueOf(value);
if (empty(stringValue) || "null".equals(stringValue) || "Optional.empty".equals(value)) { return false; }
- ITypeConverter> converter = getTypeConverter(new Class>[]{Boolean.class}, argSpec, 0);
+ ITypeConverter> converter = getTypeConverter(argSpec.auxiliaryTypes(), argSpec, 0);
return (Boolean) tryConvert(argSpec, -1, converter, stringValue, 0);
}