6

So I have a really small Spring Boot command line application (There is no embedded tomcat server or anything that would make it a web application) with a single class where I try to use the Scanner class from java.util to read input from the user. This does not work at all. I thought it would be pretty basic stuff in Spring Boot, but all of my searches both on S.O or tutorials have yielded no results. What's the best way to go about it? or is Spring Boot just not for what I want to do?

Here's my class:

package test;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.util.Scanner;

@SpringBootApplication
public class MyApplication implements CommandLineRunner {

    private static Logger LOG = LoggerFactory
        .getLogger(MyApplication.class);

    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(MyApplication.class);
        app.run(args);
    }

    @Override
    public void run(String... args) throws Exception {
        LOG.info("EXECUTING : command line runner");

        Scanner in = new Scanner(System.in);

        System.out.println("What is your name?");
        String name = in.next();
        System.out.println("Hello " + name + " welcome to spring boot" );
    }
}

The exception being thrown is:

2019-05-29 11:31:29.116  INFO 4321 --- [           main] test.MyApplication  : EXECUTING : command line runner
2019-05-29 11:31:29.119  INFO 4321 --- [           main] ConditionEvaluationReportLoggingListener : 

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2019-05-29 11:31:29.124 ERROR 4321 --- [           main] o.s.boot.SpringApplication               : Application run failed

java.lang.IllegalStateException: Failed to execute CommandLineRunner
        at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:816) ~[spring-boot-2.1.5.RELEASE.jar:2.1.5.RELEASE]
        at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:797) ~[spring-boot-2.1.5.RELEASE.jar:2.1.5.RELEASE]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:324) ~[spring-boot-2.1.5.RELEASE.jar:2.1.5.RELEASE]
        at com.jaletechs.png.PrimeNumberGeneratorApplication.main(MyApplication.java:19) [main/:na]
Caused by: java.util.NoSuchElementException: null
        at java.util.Scanner.throwFor(Scanner.java:862) ~[na:1.8.0_201]
        at java.util.Scanner.next(Scanner.java:1371) ~[na:1.8.0_201]
        at test.MyApplication.run(MyApplication.java:27) [main/:na]
        at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:813) ~[spring-boot-2.1.5.RELEASE.jar:2.1.5.RELEASE]
        ... 3 common frames omitted
jaletechs
  • 501
  • 1
  • 7
  • 19
  • Possible duplicate of [Read Console input on spring boot with tomcat](https://stackoverflow.com/questions/43315607/read-console-input-on-spring-boot-with-tomcat) – Milan Desai May 29 '19 at 11:08
  • see https://stackoverflow.com/questions/43315607/read-console-input-on-spring-boot-with-tomcat – Milan Desai May 29 '19 at 11:08
  • Please this is not a duplicate. There is no tomcat or any other server for that matter. It's just a command line application (or at least I want it to be). Every dependency that makes it a web application is deliberately absent. – jaletechs May 29 '19 at 11:44

4 Answers4

8

i follow the below approach,

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

@Component
public class MyRunner implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
        System.out.println("Enter word!");
        Scanner scanner = new Scanner(System.in);
        String line = scanner.nextLine();
        System.out.println(line);
     }
}

it works for me well, and you can combine command line listener in main class also.

parrotjack
  • 432
  • 1
  • 6
  • 18
3

Spring boot is not designed for any kind of general purpose usages. It has specific purposes. We should not always think about how to use Spring Boot for any kind of requirements. I know Spring Boot has become very popular. To your question, if you want to create an interactive application/program, you have to do in a simple manner. I just provide below the code snippet.

public class Interactive
{

  public static void main (String[] args)
  {
    // create a scanner so we can read the command-line input
    Scanner scanner = new Scanner(System.in);
    System.out.print("Enter your name ? ");
    String username = scanner.next();
    System.out.print("Enter your age ? ");
    int age = scanner.nextInt();

    //Print all name, age etc
  }

}

Hope this may be your requirement. Again Spring Boot application can not be stated as interactive in true sense. Many interpretations are there. Spring Boot is suitable for client server architecture.

Sambit
  • 7,625
  • 7
  • 34
  • 65
2

or is Spring Boot just not for what I want to do?

You are right.

Spring Boot application is a server one (like any other .war) and runs in an embedded Tomcat. What kind of Scanner here can be?

If you want to interact with it - you should create REST controller and send/receive data through endpoints.

Bor Laze
  • 2,458
  • 12
  • 20
  • 1
    You can create command line applications with spring boot (although I'm not sure it allows console interaction), so it is not just for server applications. Granted, using Spring Boot for command line is probably overkill, but it is possible (using `CommandLineRunner`) – Mark Rotteveel May 29 '19 at 18:39
1

So I discovered a way to make it work by trying out a normal gradle application (not spring boot). I ran into the same problem, and the solution was to add a line in my build.gradle file to wire up the default stdin

In a normal java gradle application:

run {
    standardInput = System.in
}

but in the Spring Boot application, I added the following line:

bootRun {
    standardInput = System.in
}

Turns out Spring Boot could handle a Command Line Application after all.

jaletechs
  • 501
  • 1
  • 7
  • 19