OptionValues supports multiple resolvers
- Change ref field in OptionValues to providers takin an array. - Relates #637
This commit is contained in:
@@ -33,8 +33,9 @@ import java.lang.annotation.Target;
|
||||
public @interface OptionValues {
|
||||
|
||||
/**
|
||||
* Reference to a bean name
|
||||
* @return a bean name
|
||||
* Names of beans for {@link CompletionProvider}.
|
||||
*
|
||||
* @return names of CompletionProvider beans
|
||||
*/
|
||||
String ref() default "";
|
||||
String[] provider() default {};
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.springframework.shell.command.annotation.support;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
@@ -38,6 +39,8 @@ import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
|
||||
import org.springframework.messaging.handler.invocation.InvocableHandlerMethod;
|
||||
import org.springframework.shell.Availability;
|
||||
import org.springframework.shell.AvailabilityProvider;
|
||||
import org.springframework.shell.CompletionContext;
|
||||
import org.springframework.shell.CompletionProposal;
|
||||
import org.springframework.shell.Utils;
|
||||
import org.springframework.shell.command.CommandExceptionResolver;
|
||||
import org.springframework.shell.command.CommandHandlingResult;
|
||||
@@ -52,6 +55,7 @@ import org.springframework.shell.command.annotation.Option;
|
||||
import org.springframework.shell.command.annotation.OptionValues;
|
||||
import org.springframework.shell.command.invocation.InvocableShellMethod;
|
||||
import org.springframework.shell.completion.CompletionProvider;
|
||||
import org.springframework.shell.completion.CompletionResolver;
|
||||
import org.springframework.shell.context.InteractionMode;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
@@ -277,12 +281,25 @@ class CommandRegistrationFactoryBean implements FactoryBean<CommandRegistration>
|
||||
}
|
||||
|
||||
OptionValues ovAnn = mp.getParameterAnnotation(OptionValues.class);
|
||||
if (ovAnn != null && StringUtils.hasText(ovAnn.ref())) {
|
||||
CompletionProvider cr = this.applicationContext.getBean(ovAnn.ref(), CompletionProvider.class);
|
||||
if (cr != null) {
|
||||
optionSpec.completion(ctx -> cr.apply(ctx));
|
||||
if (ovAnn != null) {
|
||||
String[] providerBeanNames = ovAnn.provider();
|
||||
if (providerBeanNames.length > 0) {
|
||||
final List<CompletionProvider> resolvers = Arrays.stream(providerBeanNames)
|
||||
.map(beanName -> this.applicationContext.getBean(beanName, CompletionProvider.class))
|
||||
.collect(Collectors.toList());
|
||||
optionSpec.completion(ctx -> {
|
||||
return resolvers.stream()
|
||||
.flatMap(resolver -> resolver.apply(ctx).stream())
|
||||
.collect(Collectors.toList());
|
||||
});
|
||||
}
|
||||
}
|
||||
// if (ovAnn != null && StringUtils.hasText(ovAnn.ref())) {
|
||||
// CompletionProvider cr = this.applicationContext.getBean(ovAnn.ref(), CompletionProvider.class);
|
||||
// if (cr != null) {
|
||||
// optionSpec.completion(ctx -> cr.apply(ctx));
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.shell.command.annotation.support;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
@@ -25,6 +27,8 @@ import org.springframework.shell.command.CommandRegistration;
|
||||
import org.springframework.shell.command.annotation.Command;
|
||||
import org.springframework.shell.command.annotation.CommandAvailability;
|
||||
import org.springframework.shell.command.annotation.Option;
|
||||
import org.springframework.shell.command.annotation.OptionValues;
|
||||
import org.springframework.shell.completion.CompletionProvider;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -209,6 +213,35 @@ class CommandRegistrationFactoryBeanTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void setsOptionWithCompletion() {
|
||||
configCommon(OptionWithCompletion.class, new OptionWithCompletion(), "command1", new Class[] { String.class })
|
||||
.run((context) -> {
|
||||
CommandRegistrationFactoryBean fb = context.getBean(FACTORYBEANREF,
|
||||
CommandRegistrationFactoryBean.class);
|
||||
assertThat(fb).isNotNull();
|
||||
CommandRegistration registration = fb.getObject();
|
||||
assertThat(registration).isNotNull();
|
||||
assertThat(registration.getOptions().get(0).getCompletion()).isNotNull();
|
||||
});
|
||||
}
|
||||
|
||||
@Command
|
||||
private static class OptionWithCompletion {
|
||||
|
||||
@Command
|
||||
void command1(@Option(longNames = "arg") @OptionValues(provider = "completionProvider") String arg) {
|
||||
}
|
||||
|
||||
@Bean
|
||||
CompletionProvider completionProvider() {
|
||||
return ctx -> {
|
||||
return Collections.emptyList();
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private <T> ApplicationContextRunner configCommon(Class<T> type, T bean) {
|
||||
return configCommon(type, bean, "command", new Class[0]);
|
||||
}
|
||||
|
||||
@@ -62,8 +62,8 @@ public class InteractiveCompletionCommands {
|
||||
|
||||
@Command(command = "interactive-completion-1")
|
||||
public String testRequiredValueAnnotation(
|
||||
@Option(longNames = "arg1", required = true) @OptionValues(ref = "test1CompletionProvider") String arg1,
|
||||
@Option(longNames = "arg2", required = true) @OptionValues(ref = "test2CompletionProvider") String arg2
|
||||
@Option(longNames = "arg1", required = true) @OptionValues(provider = "test1CompletionProvider") String arg1,
|
||||
@Option(longNames = "arg2", required = true) @OptionValues(provider = "test2CompletionProvider") String arg2
|
||||
) {
|
||||
return "Hello " + arg1;
|
||||
}
|
||||
@@ -79,8 +79,8 @@ public class InteractiveCompletionCommands {
|
||||
@Bean
|
||||
CompletionProvider test2CompletionProvider() {
|
||||
return ctx -> {
|
||||
Test1ValuesProvider test1ValuesProvider = new Test1ValuesProvider();
|
||||
return test1ValuesProvider.complete(ctx);
|
||||
Test2ValuesProvider test2ValuesProvider = new Test2ValuesProvider();
|
||||
return test2ValuesProvider.complete(ctx);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user