Skip to content

Command not registered if @Profile(..) is used and activatedΒ #1325

Closed

Description

@tkrah

Hi,

I got some command which have:

@Component
@Profile("solr")
public class IndexCommand {
...
}

In v3 this works like expected, if the profile solr is enabled, it gets registered.

In v4 the command is not available at all if you use @Profile(..) although the profile is activated - looks like a bug to me, anyone?

Activity

  1. fmbenhassine commented on Mar 26, 2026

    @fmbenhassine
    Contributor

    This is a valid issue. Thank you for reporting it! I will plan the fix for the upcoming release.

  2. added and removed
    status/need-triageTeam needs to triage and take a first look
    on Mar 26, 2026
  3. added this to the 4.0.2 milestone on Mar 26, 2026
  4. changed the title [-]Shell 4: Command not registered if @Profile(..) is used and activated[/-] [+]Command not registered if @Profile(..) is used and activated[/+] on Mar 26, 2026
  5. czpilar commented on Apr 1, 2026

    @czpilar
    Contributor

    Hello,

    I've just tried to reproduce the issue to help fix the problem, but I'm not sure if my configuration is correct because I'm not able to replicate the issue with the following steps.

    If I am not mistaken, the issue is about class level Profile configuration.

    So considering the following configuration:

    package org.springframework.shell.samples.helloworld.boot;
    
    import org.springframework.context.annotation.Profile;
    import org.springframework.shell.core.command.annotation.Command;
    import org.springframework.shell.core.command.annotation.Option;
    import org.springframework.stereotype.Component;
    
    @Component
    @Profile("greetings")
    public class GreetingCommands {
    
    	@Command(name = "hello", description = "Say hello to a given name", group = "Greetings",
    			help = "A command that greets the user with 'Hello ${name}!'. Usage: hello [-n | --name]=<name>")
    	public void sayHello(@Option(shortName = 'n', longName = "name", description = "the name of the person to greet",
    			defaultValue = "World") String name) {
    		System.out.println("Hello " + name + "!");
    	}
    
    }
    package org.springframework.shell.samples.helloworld.boot;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class SpringShellApplication {
    
    	public static void main(String[] args) {
    		SpringApplication.run(SpringShellApplication.class, args);
    	}
    
    }

    Running the application with an enabled profile and command is registered and works as expected:

    mvnw -pl org.springframework.shell:spring-shell-sample-spring-boot spring-boot:run -Dspring-boot.run.profiles=greetings
    

    or equivalently:

    mvnw -pl org.springframework.shell:spring-shell-sample-spring-boot spring-boot:run -Dspring-boot.run.jvmArguments="-Dspring.profiles.active=greetings"
    
    Image

    Running the application without an enabled profile and command is not registered:

    mvnw -pl org.springframework.shell:spring-shell-sample-spring-boot spring-boot:run
    
    Image
  6. fmbenhassine commented on Apr 3, 2026

    @fmbenhassine
    Contributor

    @czpilar Thank you for trying to help on this!

    I believe I validated this bug by mistake, and here is why: when I tested this back then, I used the non-boot version of the hello world sample (since the OP did not mention Boot). And here is the quick sample I used:

    package org.springframework.shell.samples.helloworld;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.annotation.Profile;
    import org.springframework.shell.core.ShellRunner;
    import org.springframework.shell.core.command.annotation.Command;
    import org.springframework.shell.core.command.annotation.EnableCommand;
    import org.springframework.shell.core.command.annotation.Option;
    import org.springframework.stereotype.Component;
    
    @EnableCommand(SpringShellApplication.class)
    public class SpringShellApplication {
    
    	public static void main(String[] args) throws Exception {
    		ApplicationContext context = new AnnotationConfigApplicationContext(SpringShellApplication.class);
    		ShellRunner runner = context.getBean(ShellRunner.class);
    		runner.run(args);
    	}
    
    	@Component
    	@Profile("greeting")
    	static class GreetingCommands {
    
    		@Command(name = "hello", description = "Say hello to a given name", group = "Greetings",
    				help = "A command that greets the user with 'Hello ${name}!'. Usage: hello [-n | --name]=<name>")
    		public void sayHello(@Option(shortName = 'n', longName = "name",
    				description = "the name of the person to greet", defaultValue = "World") String name) {
    			System.out.println("Hello " + name + "!");
    		}
    
    		@Command(name = "goodbye", description = "Say goodbye to a given name", group = "Greetings",
    				help = "A command that says goodbye to the user with 'Goodbye ${name}!'. Usage: goodbye [-n | --name]=<name>")
    		public void sayGoodbye(@Option(shortName = 'n', longName = "name",
    				description = "the name of the person to say goodbye to", defaultValue = "World") String name) {
    			System.out.println("Goodbye " + name + "!");
    		}
    
    	}
    
    }

    Running this sample with the greeting profile active does not show the commands, so I thought the bug report is valid.. but my sample was actually incorrect, it should have been like:

    --@EnableCommand(SpringShellApplication.class)
    ++@EnableCommand(SpringShellApplication.GreetingCommands.class)
    public class SpringShellApplication {
    ...
    }

    which works as expected with profiles. I just re-tested with nested and non-nested classes and profile honouring seems to work with boot and non-boot samples.

    @tkrah Can you please provide a minimal complete sample that we can use to reproduce the issue? Are you sure your IndexCommand is not excluded from classpath scanning and correctly defined as a bean?

  7. removed this from the 4.0.2 milestone on Apr 3, 2026
  8. tkrah commented on Apr 7, 2026

    @tkrah
    Author

    Got one, I reused my demo repo for my spring security issue, so please ignore the stuff which is not related.

    Go to https://github.com/tkrah/spring-sec-14911:

    You can see the command (https://github.com/tkrah/spring-sec-14911/blob/main/src/main/java/com/example/demo/shell/IndexCommand.java) is annotated with:

    
    @Component
    @Profile("solr")
    public class IndexCommand {
    

    Build it with:

    ./gradlew build -x check
    

    and start the shell with:

    ./demo-shell.sh

    This will print:

    
     :: Spring Boot ::                (v4.0.5)
    
    2026-04-07T18:32:22.679+02:00  INFO 432919 --- [demo] [           main] com.example.demo.DemoApplication         : Starting DemoApplication v0.0.1-SNAPSHOT using Java 25.0.2 with PID 432919 (/home/tkrah/Development/src/git/demo/demo/build/libs/demo-0.0.1-SNAPSHOT.jar started by tkrah in /home/tkrah/Development/src/git/demo/demo)
    2026-04-07T18:32:22.683+02:00  INFO 432919 --- [demo] [           main] com.example.demo.DemoApplication         : The following 3 profiles are active: "g_dev", "default", "solr"
    2026-04-07T18:32:23.416+02:00  WARN 432919 --- [demo] [           main] o.s.security.core.userdetails.User       : User.withDefaultPasswordEncoder() is considered unsafe for production and is only intended for sample applications.
    2026-04-07T18:32:23.865+02:00  INFO 432919 --- [demo] [           main] com.example.demo.DemoApplication         : Started DemoApplication in 1.645 seconds (process running for 2.198)
    $>help
    AVAILABLE COMMANDS
    
    Built-In Commands
    	help: Display help about available commands
    	script: Execute commands from a script file
    	quit, exit: Exit the shell
    	clear: Clear the terminal screen
    	version: Show version info
    
    $>hello
    Command hello not found
    AVAILABLE COMMANDS
    
    Built-In Commands
    	help: Display help about available commands
    	script: Execute commands from a script file
    	quit, exit: Exit the shell
    	clear: Clear the terminal screen
    	version: Show version info
    
    

    The command is not registered.

    Now remove the @Profile("solr") from the IndexCommand class, rebuild the jar and restart the shell, you will see this:

     :: Spring Boot ::                (v4.0.5)
    
    2026-04-07T18:32:56.034+02:00  INFO 433522 --- [demo] [           main] com.example.demo.DemoApplication         : Starting DemoApplication v0.0.1-SNAPSHOT using Java 25.0.2 with PID 433522 (/home/tkrah/Development/src/git/demo/demo/build/libs/demo-0.0.1-SNAPSHOT.jar started by tkrah in /home/tkrah/Development/src/git/demo/demo)
    2026-04-07T18:32:56.039+02:00  INFO 433522 --- [demo] [           main] com.example.demo.DemoApplication         : The following 3 profiles are active: "g_dev", "default", "solr"
    2026-04-07T18:32:56.752+02:00  WARN 433522 --- [demo] [           main] o.s.security.core.userdetails.User       : User.withDefaultPasswordEncoder() is considered unsafe for production and is only intended for sample applications.
    2026-04-07T18:32:57.222+02:00  INFO 433522 --- [demo] [           main] com.example.demo.DemoApplication         : Started DemoApplication in 1.673 seconds (process running for 2.202)
    $>help
    AVAILABLE COMMANDS
    
    Built-In Commands
    	help: Display help about available commands
    	script: Execute commands from a script file
    	quit, exit: Exit the shell
    	clear: Clear the terminal screen
    	version: Show version info
    Greetings
    	hello: Say hello to a given name
    
    

    Now the command is registered.

    In both cases, the profiles active are:

    The following 3 profiles are active: "g_dev", "default", "solr"

    If I am doing something wrong here, I am open to suggestions ;) .

  9. czpilar commented on Apr 7, 2026

    @czpilar
    Contributor

    I've just tried to reproduce the problem with the following configuration:

    SpringShellApplication.java

    package org.springframework.shell.samples.helloworld.boot;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class SpringShellApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SpringShellApplication.class, args);
        }
    
    }

    IndexCommand.java

    package org.springframework.shell.samples.helloworld.boot;
    
    import org.springframework.context.annotation.Profile;
    import org.springframework.shell.core.command.annotation.Command;
    import org.springframework.shell.core.command.annotation.Option;
    import org.springframework.stereotype.Component;
    
    @Component
    @Profile("solr")
    public class IndexCommand {
    
        @Command(name = "hello", description = "Say hello to a given name", group = "Greetings",
                help = "A command that greets the user with 'Hello ${name}!'. Usage: hello [-n | --name]=<name>")
        public void sayHello(@Option(shortName = 'n', longName = "name", description = "the name of the person to greet",
                defaultValue = "World") String name) {
            System.out.println("Hello " + name + "!");
        }
    
    }

    application.properties

    spring.application.name=spring-shell-hello-world
    
    spring.profiles.active=g_dev
    spring.profiles.group.g_dev=default,solr

    I can confirm that this is an issue in Spring Shell 4.0.1, as you can see in the following screenshot.

    Image

    However, with the current main branch, the issue is no longer reproducible.

    Image

    I believe it has already been fixed, as suggested in a related issue (#1327) in the following comment:
    #1327 (comment)

  10. fmbenhassine commented on Apr 8, 2026

    @fmbenhassine
    Contributor

    Thank you for checking, @czpilar ! Indeed, I believe this is fixed by 236dbc9, which now get @Component classes from the application context (with profiles applied) compared to 4.0.1 which was looking for components by scanning the classpath (without respecting profiles).

    @tkrah Thank you for the feedback and sample, and apologies for the noise about the validity of this issue.

  11. added and removed on Apr 8, 2026
  12. added this to the 4.0.2 milestone on Apr 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions