Skip to content

Commit 9830faf

Browse files
committed
Use CommandContext as method parameter
- With annotation(@command) model it's now possible to just add CommandContext and it will get resolved and doesn't cause it to appear as an option. - Fixes #779
1 parent ef3b6e1 commit 9830faf

File tree

6 files changed

+137
-8
lines changed

6 files changed

+137
-8
lines changed

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2023 the original author or authors.
2+
* Copyright 2023-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -40,6 +40,7 @@
4040
import org.springframework.shell.Availability;
4141
import org.springframework.shell.AvailabilityProvider;
4242
import org.springframework.shell.Utils;
43+
import org.springframework.shell.command.CommandContext;
4344
import org.springframework.shell.command.CommandExceptionResolver;
4445
import org.springframework.shell.command.CommandHandlingResult;
4546
import org.springframework.shell.command.CommandRegistration;
@@ -322,6 +323,10 @@ else if (ClassUtils.isAssignable(boolean.class, parameterType)){
322323
mp.initParameterNameDiscovery(new DefaultParameterNameDiscoverer());
323324
String longName = mp.getParameterName();
324325
Class<?> parameterType = mp.getParameterType();
326+
// skip known types which are coming in via parameter resolvers
327+
if (ClassUtils.isAssignable(parameterType, CommandContext.class)) {
328+
return;
329+
}
325330
if (longName != null) {
326331
log.debug("Using mp='{}' longName='{}' parameterType='{}'", mp, longName, parameterType);
327332
OptionSpec optionSpec = builder.withOption();

spring-shell-core/src/test/java/org/springframework/shell/command/AbstractCommandTests.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2022-2023 the original author or authors.
2+
* Copyright 2022-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -43,6 +43,10 @@ protected static class Pojo1 {
4343

4444
public int method1Count;
4545
public CommandContext method1Ctx;
46+
public int method1Mixed1Count;
47+
public String method1Mixed1Arg1;
48+
public CommandContext method1Mixed1Ctx;
49+
public String method1Mixed1Arg2;
4650
public int method2Count;
4751
public int method3Count;
4852
public int method4Count;
@@ -68,6 +72,13 @@ public void method1(CommandContext ctx) {
6872
method1Count++;
6973
}
7074

75+
public void method1Mixed1(String arg1, CommandContext ctx, String arg2) {
76+
method1Mixed1Arg1 = arg1;
77+
method1Mixed1Ctx = ctx;
78+
method1Mixed1Arg2 = arg2;
79+
method1Mixed1Count++;
80+
}
81+
7182
public String method2() {
7283
method2Count++;
7384
return "hi";

spring-shell-core/src/test/java/org/springframework/shell/command/CommandExecutionTests.java

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2022-2023 the original author or authors.
2+
* Copyright 2022-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -106,6 +106,81 @@ public void testMethodExecution2() {
106106
assertThat(pojo1.method1Ctx).isNotNull();
107107
}
108108

109+
@Test
110+
public void testMixedWithCtx1() {
111+
CommandRegistration r1 = CommandRegistration.builder()
112+
.command("command1")
113+
.description("help")
114+
.withOption()
115+
.longNames("arg1")
116+
.description("some arg1")
117+
.and()
118+
.withOption()
119+
.longNames("arg2")
120+
.description("some arg1")
121+
.and()
122+
.withTarget()
123+
.method(pojo1, "method1Mixed1")
124+
.and()
125+
.build();
126+
commandCatalog.register(r1);
127+
execution.evaluate(new String[] { "command1" });
128+
assertThat(pojo1.method1Mixed1Count).isEqualTo(1);
129+
assertThat(pojo1.method1Mixed1Arg1).isNull();
130+
assertThat(pojo1.method1Mixed1Ctx).isNotNull();
131+
assertThat(pojo1.method1Mixed1Arg2).isNull();
132+
}
133+
134+
@Test
135+
public void testMixedWithCtx2() {
136+
CommandRegistration r1 = CommandRegistration.builder()
137+
.command("command1")
138+
.description("help")
139+
.withOption()
140+
.longNames("arg1")
141+
.description("some arg1")
142+
.and()
143+
.withOption()
144+
.longNames("arg2")
145+
.description("some arg1")
146+
.and()
147+
.withTarget()
148+
.method(pojo1, "method1Mixed1")
149+
.and()
150+
.build();
151+
commandCatalog.register(r1);
152+
execution.evaluate(new String[] { "command1", "--arg1", "myarg1value" });
153+
assertThat(pojo1.method1Mixed1Count).isEqualTo(1);
154+
assertThat(pojo1.method1Mixed1Arg1).isEqualTo("myarg1value");
155+
assertThat(pojo1.method1Mixed1Ctx).isNotNull();
156+
assertThat(pojo1.method1Mixed1Arg2).isNull();
157+
}
158+
159+
@Test
160+
public void testMixedWithCtx3() {
161+
CommandRegistration r1 = CommandRegistration.builder()
162+
.command("command1")
163+
.description("help")
164+
.withOption()
165+
.longNames("arg1")
166+
.description("some arg1")
167+
.and()
168+
.withOption()
169+
.longNames("arg2")
170+
.description("some arg1")
171+
.and()
172+
.withTarget()
173+
.method(pojo1, "method1Mixed1")
174+
.and()
175+
.build();
176+
commandCatalog.register(r1);
177+
execution.evaluate(new String[] { "command1", "--arg1", "myarg1value", "--arg2", "myarg2value" });
178+
assertThat(pojo1.method1Mixed1Count).isEqualTo(1);
179+
assertThat(pojo1.method1Mixed1Arg1).isEqualTo("myarg1value");
180+
assertThat(pojo1.method1Mixed1Ctx).isNotNull();
181+
assertThat(pojo1.method1Mixed1Arg2).isEqualTo("myarg2value");
182+
}
183+
109184
@Test
110185
public void testMethodArgWithoutValue() {
111186
CommandRegistration r1 = CommandRegistration.builder()

spring-shell-docs/modules/ROOT/pages/commands/writing.adoc

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[[writing]]
22
= Writing
33

4-
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
4+
ifndef::snippets[:snippets: ../../../../src/test/java/org/springframework/shell/docs]
55

66
When something needs to get written into your console you can always
77
use JDK's `System.out` which then goes directly into JDK's own streams.
@@ -17,9 +17,17 @@ to return anything given `CommandContext` contains reference to
1717
include::{snippets}/WritingSnippets.java[tag=reg-terminal-writer]
1818
----
1919

20-
It's possible to autowire `Terminal` to get access to its writer.
20+
If using `@Command` you can get access to `CommandContext` and get
21+
`Terminal` from there.
2122

2223
[source, java, indent=0]
2324
----
2425
include::{snippets}/WritingSnippets.java[tag=anno-terminal-writer]
2526
----
27+
28+
It's possible to autowire `Terminal` to get access to its writer.
29+
30+
[source, java, indent=0]
31+
----
32+
include::{snippets}/WritingSnippets.java[tag=legacyanno-terminal-writer]
33+
----

spring-shell-docs/src/test/java/org/springframework/shell/docs/WritingSnippets.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2022 the original author or authors.
2+
* Copyright 2022-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,14 +18,16 @@
1818
import org.jline.terminal.Terminal;
1919

2020
import org.springframework.beans.factory.annotation.Autowired;
21+
import org.springframework.shell.command.CommandContext;
2122
import org.springframework.shell.command.CommandRegistration;
23+
import org.springframework.shell.command.annotation.Command;
2224
import org.springframework.shell.standard.ShellMethod;
2325

2426
class WritingSnippets {
2527

2628
class Dump1 {
2729

28-
// tag::anno-terminal-writer[]
30+
// tag::legacyanno-terminal-writer[]
2931
@Autowired
3032
Terminal terminal;
3133

@@ -34,6 +36,17 @@ public void example() {
3436
terminal.writer().println("hi");
3537
terminal.writer().flush();
3638
}
39+
// end::legacyanno-terminal-writer[]
40+
}
41+
42+
class Dump2 {
43+
44+
// tag::anno-terminal-writer[]
45+
@Command
46+
public void example(CommandContext ctx) {
47+
ctx.getTerminal().writer().println("hi");
48+
ctx.getTerminal().writer().flush();
49+
}
3750
// end::anno-terminal-writer[]
3851
}
3952

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

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2022-2023 the original author or authors.
2+
* Copyright 2022-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,7 +19,9 @@
1919

2020
import org.springframework.beans.factory.annotation.Autowired;
2121
import org.springframework.context.annotation.Bean;
22+
import org.springframework.shell.command.CommandContext;
2223
import org.springframework.shell.command.CommandRegistration;
24+
import org.springframework.shell.command.annotation.Command;
2325
import org.springframework.shell.standard.ShellComponent;
2426
import org.springframework.shell.standard.ShellMethod;
2527
import org.springframework.stereotype.Component;
@@ -44,6 +46,21 @@ public void writeSystemOutAnnotation() {
4446
}
4547
}
4648

49+
@Command(command = BaseE2ECommands.ANNO, group = BaseE2ECommands.GROUP)
50+
public static class Annotation extends BaseE2ECommands {
51+
52+
@Command(command = "write-terminalwriter")
53+
public void writeTerminalWriter(CommandContext ctx) {
54+
ctx.getTerminal().writer().println("hi");
55+
ctx.getTerminal().writer().flush();
56+
}
57+
58+
@Command(command = "write-systemout")
59+
public void writeSystemOut() {
60+
System.out.println("hi");
61+
}
62+
}
63+
4764
@Component
4865
public static class Registration extends BaseE2ECommands {
4966

0 commit comments

Comments
 (0)