This is an automated email from the ASF dual-hosted git repository. paulk pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/master by this push: new f44449e GROOVY-8975: GroovyCastException on the result of CliBuilder.parseFromSpec f44449e is described below commit f44449ebd615cb5d5f766a30b2a6e904084acece Author: Paul King <pa...@asert.com.au> AuthorDate: Tue Feb 19 13:08:59 2019 +1000 GROOVY-8975: GroovyCastException on the result of CliBuilder.parseFromSpec --- .../src/main/groovy/groovy/cli/commons/CliBuilder.groovy | 14 +++++++------- .../test/groovy/groovy/cli/commons/CliBuilderTest.groovy | 16 ++++++++++++++-- .../src/main/groovy/groovy/cli/picocli/CliBuilder.groovy | 9 +++++---- .../test/groovy/groovy/cli/picocli/CliBuilderTest.groovy | 14 ++++++++++++++ 4 files changed, 40 insertions(+), 13 deletions(-) diff --git a/subprojects/groovy-cli-commons/src/main/groovy/groovy/cli/commons/CliBuilder.groovy b/subprojects/groovy-cli-commons/src/main/groovy/groovy/cli/commons/CliBuilder.groovy index 218c9cb..e066ec8 100644 --- a/subprojects/groovy-cli-commons/src/main/groovy/groovy/cli/commons/CliBuilder.groovy +++ b/subprojects/groovy-cli-commons/src/main/groovy/groovy/cli/commons/CliBuilder.groovy @@ -30,11 +30,11 @@ import org.apache.commons.cli.HelpFormatter import org.apache.commons.cli.Option as CliOption import org.apache.commons.cli.Options import org.apache.commons.cli.ParseException +import org.codehaus.groovy.runtime.DefaultGroovyMethods import org.codehaus.groovy.runtime.InvokerHelper import org.codehaus.groovy.runtime.MetaClassHelper import java.lang.annotation.Annotation -import java.lang.reflect.Array import java.lang.reflect.Field import java.lang.reflect.Method @@ -388,7 +388,7 @@ class CliBuilder { def cli = parse(args) def cliOptions = [:] setOptionsFromAnnotations(cli, optionsClass, cliOptions, false) - cliOptions as T + DefaultGroovyMethods.asType(cliOptions, optionsClass) } /** @@ -419,7 +419,7 @@ class CliBuilder { } optionFields.each { Field f -> Annotation annotation = f.getAnnotation(Option) - String setterName = "set" + capitalize(f.getName()); + String setterName = "set" + capitalize(f.getName()) Method m = optionClass.getMethod(setterName, f.getType()) def typedOption = processAddAnnotation(annotation, m, true) options.addOption(typedOption.cliOption) @@ -515,7 +515,7 @@ class CliBuilder { } optionClass.declaredFields.findAll { it.getAnnotation(Option) }.each { Field f -> Annotation annotation = f.getAnnotation(Option) - String setterName = "set" + capitalize(f.getName()); + String setterName = "set" + capitalize(f.getName()) Method m = optionClass.getMethod(setterName, f.getType()) Map names = calculateNames(annotation.longName(), annotation.shortName(), m, true) processSetAnnotation(m, t, names.long ?: names.short, cli, true) @@ -525,7 +525,7 @@ class CliBuilder { processSetRemaining(m, remaining, t, cli, namesAreSetters) } optionClass.declaredFields.findAll{ it.getAnnotation(Unparsed) }.each { Field f -> - String setterName = "set" + capitalize(f.getName()); + String setterName = "set" + capitalize(f.getName()) Method m = optionClass.getMethod(setterName, f.getType()) processSetRemaining(m, remaining, t, cli, namesAreSetters) } @@ -538,12 +538,12 @@ class CliBuilder { def type = null if (isTyped) { type = resultType.componentType - result = remaining.collect{ cli.getValue(type, it, null) } + result = remaining.collect{ cli.getValue(type, it, null) }.asType(resultType) } else { result = remaining.toList() } if (namesAreSetters) { - m.invoke(t, isTyped ? [result.toArray(Array.newInstance(type, result.size()))] as Object[] : result) + m.invoke(t, isTyped ? [result] as Object[] : result) } else { Map names = calculateNames("", "", m, namesAreSetters) t.put(names.long, { -> result }) diff --git a/subprojects/groovy-cli-commons/src/test/groovy/groovy/cli/commons/CliBuilderTest.groovy b/subprojects/groovy-cli-commons/src/test/groovy/groovy/cli/commons/CliBuilderTest.groovy index fd8928a..0d4d5a5 100644 --- a/subprojects/groovy-cli-commons/src/test/groovy/groovy/cli/commons/CliBuilderTest.groovy +++ b/subprojects/groovy-cli-commons/src/test/groovy/groovy/cli/commons/CliBuilderTest.groovy @@ -622,7 +622,6 @@ usage: groovy @Unparsed Integer[] nums() } - // this feature is incubating void testTypedUnparsedFromSpec() { def argz = '12 34 56'.split() def cli = new CliBuilder() @@ -634,7 +633,6 @@ usage: groovy @Unparsed Integer[] nums } - // this feature is incubating void testTypedUnparsedFromInstance() { def argz = '12 34 56'.split() def cli = new CliBuilder() @@ -661,6 +659,20 @@ usage: groovy } } + interface StringIntArray { + @Option(shortName='u') String user() + @Unparsed Integer[] nums() + } + + // GROOVY-8975 + void testTypedCaseWithRemainingArray() { + def cli = new CliBuilder() + def argz = '--user abc 12 34'.split() + StringIntArray hello = cli.parseFromSpec(StringIntArray, argz) + assert hello.user() == 'abc' + assert hello.nums() == [12, 34] + } + void testParseFromInstanceFlagEdgeCases() { def cli = new CliBuilder() def options = cli.parseFromSpec(FlagEdgeCasesI, '-abc -efg true --ijk foo --lmn bar baz'.split()) diff --git a/subprojects/groovy-cli-picocli/src/main/groovy/groovy/cli/picocli/CliBuilder.groovy b/subprojects/groovy-cli-picocli/src/main/groovy/groovy/cli/picocli/CliBuilder.groovy index e53003e..914360a 100644 --- a/subprojects/groovy-cli-picocli/src/main/groovy/groovy/cli/picocli/CliBuilder.groovy +++ b/subprojects/groovy-cli-picocli/src/main/groovy/groovy/cli/picocli/CliBuilder.groovy @@ -23,6 +23,7 @@ import groovy.cli.Option import groovy.cli.TypedOption import groovy.cli.Unparsed import groovy.transform.Undefined +import org.codehaus.groovy.runtime.DefaultGroovyMethods import org.codehaus.groovy.runtime.InvokerHelper import org.codehaus.groovy.runtime.MetaClassHelper import picocli.CommandLine @@ -658,7 +659,7 @@ class CliBuilder { addOptionsFromAnnotations(optionsClass, cliOptions, true) addPositionalsFromAnnotations(optionsClass, cliOptions, true) parse(args) - cliOptions as T + DefaultGroovyMethods.asType(cliOptions, optionsClass) } /** @@ -786,7 +787,7 @@ class CliBuilder { private ArgSpecAttributes extractAttributesFromField(Field f, target) { def getter = { f.accessible = true - f.get(target); + f.get(target) } def setter = { newValue -> f.accessible = true @@ -799,7 +800,7 @@ class CliBuilder { } private PositionalParamSpec createPositionalParamSpec(Unparsed unparsed, ArgSpecAttributes attr, Object target) { - PositionalParamSpec.Builder builder = PositionalParamSpec.builder(); + PositionalParamSpec.Builder builder = PositionalParamSpec.builder() CommandLine.Range arity = CommandLine.Range.valueOf("0..*") if (attr.type == Object) { attr.type = String[] } @@ -922,7 +923,7 @@ class CliBuilder { } /** Commons-cli constant that specifies the number of argument values is infinite */ - private static final int COMMONS_CLI_UNLIMITED_VALUES = -2; + private static final int COMMONS_CLI_UNLIMITED_VALUES = -2 // - argName: String // - longOpt: String diff --git a/subprojects/groovy-cli-picocli/src/test/groovy/groovy/cli/picocli/CliBuilderTest.groovy b/subprojects/groovy-cli-picocli/src/test/groovy/groovy/cli/picocli/CliBuilderTest.groovy index 6740781..6849d3c 100644 --- a/subprojects/groovy-cli-picocli/src/test/groovy/groovy/cli/picocli/CliBuilderTest.groovy +++ b/subprojects/groovy-cli-picocli/src/test/groovy/groovy/cli/picocli/CliBuilderTest.groovy @@ -990,6 +990,20 @@ class CliBuilderTest extends GroovyTestCase { } } + interface StringIntArray { + @Option(shortName='u') String user() + @Unparsed Integer[] nums() + } + + // GROOVY-8975 + void testTypedCaseWithRemainingArray() { + def cli = new CliBuilder() + def argz = '--user abc 12 34'.split() + StringIntArray hello = cli.parseFromSpec(StringIntArray, argz) + assert hello.user() == 'abc' + assert hello.nums() == [12, 34] + } + void testAcceptLongOptionsWithSingleHyphen_usage() { resetPrintWriter() CliBuilder cli = new CliBuilder(acceptLongOptionsWithSingleHyphen: true, writer: printWriter)