Skip to content

NonInteractiveShellRunner v3 -> v4 Migration IssueΒ #1312

Closed

Description

@rmcdouga

I am encountering an issue with a Spring Shell v4 non-interactive application. When running the application in a Windows terminal, output that contains UTF-8 characters outside the BMP displays those characters as question marks.

I believe that this is because the NonInteractiveShellRunner uses System.console for output which uses the terminal's default character set (IBM437). The JLine library supports writing unicode characters out to the console, so using it resolves this issue.

This is a Spring Shell v3 to v4 Migration issue. Under Spring Shell v3, non-interactive applications still used JLine for console output but under Spring Shell v4, System.console is used.

It would be nice if the JLine library made a non-interactive ShellRunner class available to replace the default NonInteractiveShellRunner in order to make the JLine capabilities available when the JLine starter is used.

The following code demonstrates the issue in Spring Shell v4:

package io.github.rmcdouga;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.shell.core.command.annotation.Command;

@SpringBootApplication
public class DemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
	}

	@Command(name = "example")
	public String example() {
		return "Hello World! \u2665";	// Should display a heart symbol but displays question mark instead.
	}
}

The equivilent code works under Spring Shell v3:

package io.github.rmcdouga;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.shell.command.annotation.Command;
import org.springframework.shell.command.annotation.CommandScan;

@SpringBootApplication
@CommandScan
@Command
public class DemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
	}

	@Command(command = "example")
	public String example() {
		return "Hello World! \u2665"; // Displays a heart symbol
	}
}

Activity

  1. changed the title [-]New JLineNonInteractiveShellRunner Class[/-] [+]NonInteractiveShellRunner v3 -> v4 Migration Issue[/+] on Feb 3, 2026
  2. czpilar commented on Feb 10, 2026

    @czpilar
    Contributor

    Fixed in PR #1319

    Image
  3. czpilar commented on Feb 10, 2026

    @czpilar
    Contributor

    It is also possible use following configuration as workaround and define your own non interactive shell runner:

    package org.springframework.shell.samples.helloworld.boot;
    
    import org.jline.terminal.Terminal;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Primary;
    import org.springframework.shell.core.NonInteractiveShellRunner;
    import org.springframework.shell.core.ShellRunner;
    import org.springframework.shell.core.command.CommandParser;
    import org.springframework.shell.core.command.CommandRegistry;
    import org.springframework.shell.core.command.annotation.Command;
    
    @SpringBootApplication
    public class SpringShellApplication {
    
    	public static void main(String[] args) {
    		SpringApplication.run(SpringShellApplication.class, args);
    	}
    
    	@Command(name = "example")
    	public String example() {
    		return "Hello World! \u2665"; // Should display a heart symbol but displays question mark instead.
    	}
    
    	@Bean
    	@Primary
    	public ShellRunner jlineNonInteractiveShellRunner(CommandParser commandParser, CommandRegistry commandRegistry, Terminal terminal) {
    		return new NonInteractiveShellRunner(commandParser, commandRegistry, terminal.writer());
    	}
    
    }
  4. fmbenhassine commented on Mar 25, 2026

    @fmbenhassine
    Contributor

    Thank you for reporting this, @rmcdouga , this is a valid issue. If JLine is present, a JLine capable shell should be used by default (be it interactive or not).

    I will plan the fix for 4.0.2.

    @czpilar Thank you for the follow up and the PR!

  5. added and removed
    status/need-triageTeam needs to triage and take a first look
    on Mar 25, 2026
  6. added this to the 4.0.2 milestone on Mar 25, 2026
  7. added a commit that references this issue on Mar 25, 2026
    f701dd9
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