skip to content

How does command Availability work in Spring Shell, and how do you make a command temporarily unavailable?

level: seniorimportance: should knowfreq 30%

answer

  1. Availability.available() / unavailable("reason")
  2. Convention: <command>Availability() method
  3. @ShellMethodAvailability to link by name/keys
  4. Unavailable = listed in help but refuses to run
  5. Checked per invocation, reflects live state

basics

~20 s

You provide a method returning Availability that returns Availability.available() or Availability.unavailable("reason"). Spring Shell links it by naming convention (commandNameAvailability) or via @ShellMethodAvailability. Unavailable commands still list in help but refuse to run with the reason.

solid answer

~40 s

Availability lets a command be enabled or disabled based on runtime state — for example a `download` command only works after `connect`. You write a no-arg method returning the `Availability` type: return `Availability.available()` to enable it, or `Availability.unavailable("you are not connected")` to disable it with an explanation. Spring Shell binds the availability method to the command in two ways: (1) by convention, a method named `<commandMethodName>Availability` (e.g. `download` -> `downloadAvailability`) is auto-detected; (2) explicitly with `@ShellMethodAvailability("methodRef")` on the command, or on the availability method pointing back at command names. An unavailable command still appears in `help` (listed as currently unavailable) but invoking it prints the reason and does not execute the body. This is evaluated per invocation, so it reflects current state.

code

java · 24 lines
java
@ShellComponent
public class RemoteCommands {
    private boolean connected = false;

    @ShellMethod("Connect to the server")
    public String connect() { connected = true; return "connected"; }

    @ShellMethod("Download a file")
    public String download(String path) { return "downloading " + path; }

    // Convention: download -> downloadAvailability
    public Availability downloadAvailability() {
        return connected
            ? Availability.available()
            : Availability.unavailable("you are not connected");
    }

    // Explicit form sharing one check across commands:
    @ShellMethodAvailability({"upload", "sync"})
    public Availability requiresConnection() {
        return connected ? Availability.available()
                         : Availability.unavailable("you are not connected");
    }
}

go deeper

for a junior

Aware that commands can be conditionally enabled.

for a middle

Can write an availability method and return available()/unavailable().

for a senior

Knows both wiring styles, per-invocation evaluation, and help behavior for unavailable commands.

for a principal

Distinguishes availability (UX) from authorization; designs stateful command lifecycles and shared availability checks across a suite.

**The problem it solves.** Some commands only make sense in certain states. You do not want to scatter `if (!connected) return error;` guards through every method. Spring Shell's *availability* mechanism centralizes that: the framework asks "is this command available right now?" before running it and before letting the user rely on it. **The Availability type.** `org.springframework.shell.Availability` is a small value object with two factory methods: - `Availability.available()` — the command can run. - `Availability.unavailable(String reason)` — the command is disabled; `reason` should read grammatically after "this command is not available because ..." (e.g. `unavailable("you are not connected")`). **Wiring an availability method to a command.** Two approaches: 1. **Naming convention.** Declare a public no-arg method returning `Availability` named `<commandMethodName>Availability`. For a command method `download`, the method `downloadAvailability()` is automatically associated. No annotation needed. 2. **Explicit `@ShellMethodAvailability`.** Put `@ShellMethodAvailability("customCheck")` on the `@ShellMethod` to name the availability method, decoupling the names. Alternatively annotate the availability method itself with `@ShellMethodAvailability({"download", "upload"})` listing the command *keys* it governs — handy to share one check across several commands. Placing `@ShellMethodAvailability` at class level with no value can apply to all commands in the component. **Evaluation timing.** Availability is checked at invocation time (and used to render help state), so it reflects live state held in the bean (e.g. a `connected` field toggled by other commands). It is not a one-time startup decision. **User-visible behavior.** In `help`, unavailable commands are listed and marked as currently unavailable. If the user runs an unavailable command, Spring Shell does not execute the method body; it prints a message like "Command 'download' exists but is not currently available because you are not connected." and suggests checking availability. **Edge cases / gotchas.** - The availability method must return `Availability` and take no arguments; a wrong signature is silently not linked (nothing enforces the convention name matches a real command). - If both a conventionally named method and an explicit annotation exist, the explicit one wins. - Availability differs from *security/authorization*; it is UX-level gating, not an access-control boundary. - Because it reads mutable bean state, keep that state thread-consistent (the shell is typically single-threaded interactively, but scripts/async change that). **When to use.** Stateful CLIs (connect/disconnect, login/logout, load-a-file-then-operate), feature flags, or environment gating where you want clear, discoverable reasons rather than opaque failures.

  • What are the two ways Spring Shell associates an availability method with a command?
    By naming convention (<commandMethod>Availability), or explicitly via @ShellMethodAvailability — on the command naming the method, or on the availability method listing the command keys it governs.
  • Is availability a substitute for authorization?
    No. It is UX-level gating that hides/blocks commands with a reason. Real access control belongs in the underlying services/security layer; availability just improves discoverability and error messaging.

saying these in an interview costs you the question

  • Claiming an unavailable command disappears from help (it is still listed, just marked unavailable)
  • Thinking availability is evaluated once at startup rather than per invocation
  • Treating availability as a security/authorization mechanism
  • Giving the availability method arguments or a non-Availability return type

context