Skip to content

Commit eaa3e5c

Browse files
committed
OptionValues supports multiple resolvers
- Change ref field in OptionValues to providers takin an array. - Relates spring-projects#637
1 parent d4506d2 commit eaa3e5c

File tree

4 files changed

+62
-11
lines changed

4 files changed

+62
-11
lines changed

spring-shell-core/src/main/java/org/springframework/shell/command/annotation/OptionValues.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,9 @@
3333
public @interface OptionValues {
3434

3535
/**
36-
* Reference to a bean name
37-
* @return a bean name
36+
* Names of beans for {@link CompletionProvider}.
37+
*
38+
* @return names of CompletionProvider beans
3839
*/
39-
String ref() default "";
40+
String[] provider() default {};
4041
}

spring-shell-core/src/main/java/org/springframework/shell/command/annotation/support/CommandRegistrationFactoryBean.java

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import java.lang.reflect.Method;
1919
import java.util.ArrayList;
20+
import java.util.Arrays;
2021
import java.util.List;
2122
import java.util.stream.Collectors;
2223
import java.util.stream.Stream;
@@ -38,6 +39,8 @@
3839
import org.springframework.messaging.handler.invocation.InvocableHandlerMethod;
3940
import org.springframework.shell.Availability;
4041
import org.springframework.shell.AvailabilityProvider;
42+
import org.springframework.shell.CompletionContext;
43+
import org.springframework.shell.CompletionProposal;
4144
import org.springframework.shell.Utils;
4245
import org.springframework.shell.command.CommandExceptionResolver;
4346
import org.springframework.shell.command.CommandHandlingResult;
@@ -52,6 +55,7 @@
5255
import org.springframework.shell.command.annotation.OptionValues;
5356
import org.springframework.shell.command.invocation.InvocableShellMethod;
5457
import org.springframework.shell.completion.CompletionProvider;
58+
import org.springframework.shell.completion.CompletionResolver;
5559
import org.springframework.shell.context.InteractionMode;
5660
import org.springframework.util.ClassUtils;
5761
import org.springframework.util.ObjectUtils;
@@ -277,12 +281,25 @@ else if (ClassUtils.isAssignable(boolean.class, parameterType)){
277281
}
278282

279283
OptionValues ovAnn = mp.getParameterAnnotation(OptionValues.class);
280-
if (ovAnn != null && StringUtils.hasText(ovAnn.ref())) {
281-
CompletionProvider cr = this.applicationContext.getBean(ovAnn.ref(), CompletionProvider.class);
282-
if (cr != null) {
283-
optionSpec.completion(ctx -> cr.apply(ctx));
284+
if (ovAnn != null) {
285+
String[] providerBeanNames = ovAnn.provider();
286+
if (providerBeanNames.length > 0) {
287+
final List<CompletionProvider> resolvers = Arrays.stream(providerBeanNames)
288+
.map(beanName -> this.applicationContext.getBean(beanName, CompletionProvider.class))
289+
.collect(Collectors.toList());
290+
optionSpec.completion(ctx -> {
291+
return resolvers.stream()
292+
.flatMap(resolver -> resolver.apply(ctx).stream())
293+
.collect(Collectors.toList());
294+
});
284295
}
285296
}
297+
// if (ovAnn != null && StringUtils.hasText(ovAnn.ref())) {
298+
// CompletionProvider cr = this.applicationContext.getBean(ovAnn.ref(), CompletionProvider.class);
299+
// if (cr != null) {
300+
// optionSpec.completion(ctx -> cr.apply(ctx));
301+
// }
302+
// }
286303

287304
}
288305
}

spring-shell-core/src/test/java/org/springframework/shell/command/annotation/support/CommandRegistrationFactoryBeanTests.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
*/
1616
package org.springframework.shell.command.annotation.support;
1717

18+
import java.util.Collections;
19+
1820
import org.junit.jupiter.api.Test;
1921

2022
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
@@ -25,6 +27,8 @@
2527
import org.springframework.shell.command.annotation.Command;
2628
import org.springframework.shell.command.annotation.CommandAvailability;
2729
import org.springframework.shell.command.annotation.Option;
30+
import org.springframework.shell.command.annotation.OptionValues;
31+
import org.springframework.shell.completion.CompletionProvider;
2832

2933
import static org.assertj.core.api.Assertions.assertThat;
3034

@@ -209,6 +213,35 @@ void command4(Boolean arg) {
209213
}
210214
}
211215

216+
@Test
217+
void setsOptionWithCompletion() {
218+
configCommon(OptionWithCompletion.class, new OptionWithCompletion(), "command1", new Class[] { String.class })
219+
.run((context) -> {
220+
CommandRegistrationFactoryBean fb = context.getBean(FACTORYBEANREF,
221+
CommandRegistrationFactoryBean.class);
222+
assertThat(fb).isNotNull();
223+
CommandRegistration registration = fb.getObject();
224+
assertThat(registration).isNotNull();
225+
assertThat(registration.getOptions().get(0).getCompletion()).isNotNull();
226+
});
227+
}
228+
229+
@Command
230+
private static class OptionWithCompletion {
231+
232+
@Command
233+
void command1(@Option(longNames = "arg") @OptionValues(provider = "completionProvider") String arg) {
234+
}
235+
236+
@Bean
237+
CompletionProvider completionProvider() {
238+
return ctx -> {
239+
return Collections.emptyList();
240+
};
241+
}
242+
243+
}
244+
212245
private <T> ApplicationContextRunner configCommon(Class<T> type, T bean) {
213246
return configCommon(type, bean, "command", new Class[0]);
214247
}

spring-shell-samples/src/main/java/org/springframework/shell/samples/e2e/InteractiveCompletionCommands.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@ public static class Annotation extends BaseE2ECommands {
6262

6363
@Command(command = "interactive-completion-1")
6464
public String testRequiredValueAnnotation(
65-
@Option(longNames = "arg1", required = true) @OptionValues(ref = "test1CompletionProvider") String arg1,
66-
@Option(longNames = "arg2", required = true) @OptionValues(ref = "test2CompletionProvider") String arg2
65+
@Option(longNames = "arg1", required = true) @OptionValues(provider = "test1CompletionProvider") String arg1,
66+
@Option(longNames = "arg2", required = true) @OptionValues(provider = "test2CompletionProvider") String arg2
6767
) {
6868
return "Hello " + arg1;
6969
}
@@ -79,8 +79,8 @@ CompletionProvider test1CompletionProvider() {
7979
@Bean
8080
CompletionProvider test2CompletionProvider() {
8181
return ctx -> {
82-
Test1ValuesProvider test1ValuesProvider = new Test1ValuesProvider();
83-
return test1ValuesProvider.complete(ctx);
82+
Test2ValuesProvider test2ValuesProvider = new Test2ValuesProvider();
83+
return test2ValuesProvider.complete(ctx);
8484
};
8585
}
8686
}

0 commit comments

Comments
 (0)