Handle collection types in a parser

- Handle any option collection type so that list is generated for
  values, this then works well when actual type conversions happen.
- Backport #630
- Fixes #631
This commit is contained in:
Janne Valkealahti
2023-01-19 17:33:18 +00:00
parent 78da071e86
commit 1bc26c7e17
3 changed files with 135 additions and 0 deletions

View File

@@ -18,10 +18,12 @@ package org.springframework.shell.command;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Deque;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -466,6 +468,13 @@ public interface CommandParser {
else if (type != null && type.isArray()) {
value = arguments.stream().collect(Collectors.toList()).toArray();
}
// if it looks like type is a collection just get as list
// as conversion will happen later. we just need to know
// if user has Set, List, Collection, etc without worrying
// about generics.
else if (type != null && type.asCollection() != ResolvableType.NONE) {
value = arguments.stream().collect(Collectors.toList());
}
else {
if (!arguments.isEmpty()) {
if (arguments.size() == 1) {

View File

@@ -310,6 +310,39 @@ public class CommandParserTests extends AbstractCommandTests {
assertThat(results.results().get(0).value()).isEqualTo(new int[] { 1, 2 });
}
@Test
public void testLongOptionsWithStringArray() {
CommandOption option1 = longOption("arg1", ResolvableType.forType(String[].class));
List<CommandOption> options = Arrays.asList(option1);
String[] args = new String[]{"--arg1", "1", "2"};
CommandParserResults results = parser.parse(options, args);
assertThat(results.results()).hasSize(1);
assertThat(results.results().get(0).option()).isSameAs(option1);
assertThat(results.results().get(0).value()).isEqualTo(new String[] { "1", "2" });
}
@Test
public void testLongOptionsWithPlainList() {
CommandOption option1 = longOption("arg1", ResolvableType.forType(List.class));
List<CommandOption> options = Arrays.asList(option1);
String[] args = new String[]{"--arg1", "1", "2"};
CommandParserResults results = parser.parse(options, args);
assertThat(results.results()).hasSize(1);
assertThat(results.results().get(0).option()).isSameAs(option1);
assertThat(results.results().get(0).value()).isEqualTo(Arrays.asList("1", "2"));
}
@Test
public void testLongOptionsWithTypedList() {
CommandOption option1 = longOption("arg1", ResolvableType.forClassWithGenerics(List.class, String.class));
List<CommandOption> options = Arrays.asList(option1);
String[] args = new String[]{"--arg1", "1", "2"};
CommandParserResults results = parser.parse(options, args);
assertThat(results.results()).hasSize(1);
assertThat(results.results().get(0).option()).isSameAs(option1);
assertThat(results.results().get(0).value()).isEqualTo(Arrays.asList("1", "2"));
}
@Test
public void testArityErrors() {
CommandOption option1 = CommandOption.of(