Use correct type with set
- When target is set and only one option argument is given, we should not convert to list as user expects string to xxx Converter to work. - This is how it used to work and previous changes caused regression. - Bug is actually in an old parser and new parser works fine. - Backport #667 - Fixes #670
This commit is contained in:
@@ -478,9 +478,16 @@ public interface CommandParser {
|
||||
// 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.
|
||||
// about generics. handle explicit size 1 so that we're
|
||||
// able to handle string to xxx converter as that what
|
||||
// user expects.
|
||||
else if (type != null && type.asCollection() != ResolvableType.NONE) {
|
||||
value = arguments.stream().collect(Collectors.toList());
|
||||
if (arguments.size() == 1) {
|
||||
value = arguments.get(0);
|
||||
}
|
||||
else {
|
||||
value = arguments.stream().collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!arguments.isEmpty()) {
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright 2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.shell.samples.e2e;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.shell.command.CommandRegistration;
|
||||
import org.springframework.shell.standard.ShellComponent;
|
||||
import org.springframework.shell.standard.ShellMethod;
|
||||
import org.springframework.shell.standard.ShellOption;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
public class OptionConversionCommands {
|
||||
|
||||
@ShellComponent
|
||||
public static class LegacyAnnotation extends BaseE2ECommands {
|
||||
|
||||
@ShellMethod(key = LEGACY_ANNO + "option-conversion-integer", group = GROUP)
|
||||
public String optionConversionIntegerAnnotation(
|
||||
@ShellOption Integer arg1
|
||||
) {
|
||||
return "Hello " + arg1;
|
||||
}
|
||||
|
||||
@ShellMethod(key = LEGACY_ANNO + "option-conversion-custom", group = GROUP)
|
||||
public String optionConversionCustomAnnotation(
|
||||
@ShellOption MyPojo arg1
|
||||
) {
|
||||
return "Hello " + arg1;
|
||||
}
|
||||
|
||||
@ShellMethod(key = LEGACY_ANNO + "option-conversion-customset", group = GROUP)
|
||||
public String optionConversionCustomSetAnnotation(
|
||||
@ShellOption Set<MyPojo> arg1
|
||||
) {
|
||||
return "Hello " + arg1;
|
||||
}
|
||||
|
||||
@ShellMethod(key = LEGACY_ANNO + "option-conversion-customarray", group = GROUP)
|
||||
public String optionConversionCustomArrayAnnotation(
|
||||
@ShellOption MyPojo[] arg1
|
||||
) {
|
||||
return "Hello " + Arrays.asList(arg1);
|
||||
}
|
||||
}
|
||||
|
||||
@Component
|
||||
public static class Registration extends BaseE2ECommands {
|
||||
|
||||
@Bean
|
||||
public CommandRegistration optionConversionIntegerRegistration() {
|
||||
return getBuilder()
|
||||
.command(REG, "option-conversion-integer")
|
||||
.group(GROUP)
|
||||
.withOption()
|
||||
.longNames("arg1")
|
||||
.type(Integer.class)
|
||||
.and()
|
||||
.withTarget()
|
||||
.function(ctx -> {
|
||||
Integer arg1 = ctx.getOptionValue("arg1");
|
||||
return "Hello " + arg1;
|
||||
})
|
||||
.and()
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CommandRegistration optionConversionCustomRegistration() {
|
||||
return getBuilder()
|
||||
.command(REG, "option-conversion-custom")
|
||||
.group(GROUP)
|
||||
.withOption()
|
||||
.longNames("arg1")
|
||||
.type(MyPojo.class)
|
||||
.and()
|
||||
.withTarget()
|
||||
.function(ctx -> {
|
||||
MyPojo arg1 = ctx.getOptionValue("arg1");
|
||||
return "Hello " + arg1;
|
||||
})
|
||||
.and()
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CommandRegistration optionConversionCustomSetRegistration() {
|
||||
return getBuilder()
|
||||
.command(REG, "option-conversion-customset")
|
||||
.group(GROUP)
|
||||
.withOption()
|
||||
.longNames("arg1")
|
||||
.type(Set.class)
|
||||
.and()
|
||||
.withTarget()
|
||||
.function(ctx -> {
|
||||
Set<MyPojo> arg1 = ctx.getOptionValue("arg1");
|
||||
return "Hello " + arg1;
|
||||
})
|
||||
.and()
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CommandRegistration optionConversionCustomArrayRegistration() {
|
||||
return getBuilder()
|
||||
.command(REG, "option-conversion-customarray")
|
||||
.group(GROUP)
|
||||
.withOption()
|
||||
.longNames("arg1")
|
||||
.type(MyPojo[].class)
|
||||
.and()
|
||||
.withTarget()
|
||||
.function(ctx -> {
|
||||
MyPojo[] arg1 = ctx.getOptionValue("arg1");
|
||||
return "Hello " + Arrays.asList(arg1);
|
||||
})
|
||||
.and()
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public static class CommonConfiguration {
|
||||
|
||||
@Bean
|
||||
public Converter<String, MyPojo> stringToMyPojoConverter() {
|
||||
return new StringToMyPojoConverter();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Converter<String, Set<MyPojo>> stringToMyPojoSetConverter() {
|
||||
return new StringToMyPojoSetConverter();
|
||||
}
|
||||
}
|
||||
|
||||
public static class MyPojo {
|
||||
private String arg;
|
||||
|
||||
public MyPojo(String arg) {
|
||||
this.arg = arg;
|
||||
}
|
||||
|
||||
public String getArg() {
|
||||
return arg;
|
||||
}
|
||||
|
||||
public void setArg(String arg) {
|
||||
this.arg = arg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MyPojo [arg=" + arg + "]";
|
||||
}
|
||||
}
|
||||
|
||||
static class StringToMyPojoConverter implements Converter<String, MyPojo> {
|
||||
|
||||
@Override
|
||||
public MyPojo convert(String from) {
|
||||
return new MyPojo(from);
|
||||
}
|
||||
}
|
||||
|
||||
static class StringToMyPojoSetConverter implements Converter<String, Set<MyPojo>> {
|
||||
|
||||
@Override
|
||||
public Set<MyPojo> convert(String from) {
|
||||
Set<MyPojo> set = new HashSet<>();
|
||||
set.add(new MyPojo(from));
|
||||
return set;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.shell.samples.e2e;
|
||||
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
|
||||
import org.springframework.shell.samples.AbstractSampleTests;
|
||||
import org.springframework.shell.samples.e2e.OptionConversionCommands.CommonConfiguration;
|
||||
import org.springframework.shell.samples.e2e.OptionConversionCommands.LegacyAnnotation;
|
||||
import org.springframework.shell.samples.e2e.OptionConversionCommands.Registration;
|
||||
import org.springframework.shell.test.ShellTestClient.BaseShellSession;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
@ContextConfiguration(classes = { LegacyAnnotation.class, Registration.class, CommonConfiguration.class })
|
||||
class OptionConversionCommandsTests extends AbstractSampleTests {
|
||||
|
||||
@ParameterizedTest
|
||||
@E2ESource(command = "option-conversion-integer --arg1 1")
|
||||
void optionConversionInteger(String command, boolean interactive) {
|
||||
BaseShellSession<?> session = createSession(command, interactive);
|
||||
assertScreenContainsText(session, "Hello 1");
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@E2ESource(command = "option-conversion-custom --arg1 hi")
|
||||
void optionConversionCustom(String command, boolean interactive) {
|
||||
BaseShellSession<?> session = createSession(command, interactive);
|
||||
assertScreenContainsText(session, "Hello MyPojo [arg=hi]");
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@E2ESource(command = "option-conversion-customset --arg1 hi")
|
||||
void optionConversionCustomSet(String command, boolean interactive) {
|
||||
BaseShellSession<?> session = createSession(command, interactive);
|
||||
assertScreenContainsText(session, "Hello [MyPojo [arg=hi]]");
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@E2ESource(command = "option-conversion-customarray --arg1 hi")
|
||||
void optionConversionCustomArray(String command, boolean interactive) {
|
||||
BaseShellSession<?> session = createSession(command, interactive);
|
||||
assertScreenContainsText(session, "Hello [MyPojo [arg=hi]]");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user