在 Eclipse IDE 中支持 java.io. Console

我使用 EclipseIDE 来开发、编译和运行我的 Java 项目。今天,我尝试使用 java.io.Console类来管理输出,更重要的是,管理用户输入。

问题是当应用程序“通过”Eclipse 运行时,System.console()返回 null。Eclipse 在后台进程上运行程序,而不是使用我们熟悉的控制台窗口的顶级进程。

有没有一种方法可以强制 Eclipse 将程序作为顶级进程运行,或者至少创建一个 JVM 可以识别的控制台?否则,我将不得不启动该项目,并在 Eclipse 外部的命令行环境上运行。

96715 次浏览

As far as I can tell, there is no way to get a Console object from Eclipse. I'd just make sure that console != null, then JAR it up and run it from the command line.

The reason this occurs is because eclipse runs your app as a background process and not as a top-level process with a system console.

Found something about this at http://www.stupidjavatricks.com/?p=43 .

And sadly, since console is final, you can't extend it to create a a wrapper around system.in and system.out that does it either. Even inside the eclipse console you still have access to those. Thats probably why eclipse hasn't plugged this into their console yet...

I understand why you wouldn't want to have any other way to get a console other than System.console, with no setter, but i don't understand why you wouldn't want someone to be able to override the class to make a mock/testing console...

There seems to be no way to get a java.io.Console object when running an application through Eclipse. A command-line console window is not opened with the application, as it is run as a background process (background to Eclipse?). Currently, there is no Eclipse plugin to handle this issue, mainly due to the fact that java.io.Console is a final class.

All you can really do is test the returned Console object for null and proceed from there.

I assume you want to be able to use step-through debugging from Eclipse. You can just run the classes externally by setting the built classes in the bin directories on the JRE classpath.

java -cp workspace\p1\bin;workspace\p2\bin foo.Main

You can debug using the remote debugger and taking advantage of the class files built in your project.

In this example, the Eclipse project structure looks like this:

workspace\project\
\.classpath
\.project
\debug.bat
\bin\Main.class
\src\Main.java

1. Start the JVM Console in Debug Mode

debug.bat is a Windows batch file that should be run externally from a cmd.exe console.

@ECHO OFF
SET A_PORT=8787
SET A_DBG=-Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,address=%A_PORT%,server=y,suspend=y
java.exe %A_DBG% -cp .\bin Main

In the arguments, the debug port has been set to 8787. The suspend=y argument tells the JVM to wait until the debugger attaches.

2. Create a Debug Launch Configuration

In Eclipse, open the Debug dialog (Run > Open Debug Dialog...) and create a new Remote Java Application configuration with the following settings:

  • Project: your project name
  • Connection Type: Standard (Socket Attach)
  • Host: localhost
  • Port: 8787

3. Debugging

So, all you have to do any time you want to debug the app is:

  • set a break point
  • launch the batch file in a console
  • launch the debug configuration

You can track this issue in bug 122429. You can work round this issue in your application by using an abstraction layer as described here.

The workaround that I use is to just use System.in/System.out instead of Console when using Eclipse. For example, instead of:

String line = System.console().readLine();

You can use:

BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
String line = bufferedReader.readLine();

This link offers alternatives to using System.console(). One is to use a BufferedReader wrapped around System.in, the second is to use a Scanner wrapped around System.in.

Neither are as concise as console, but both work in eclipse without having to resort to debug silliness!

Another option is to create a method to wrap up both options, and "fail over" to the System.in method when Console isn't available. The below example is a fairly basic one - you can follow the same process to wrap up the other methods in Console (readPassword, format) as required. That way you can run it happily in Eclipse & when its deployed you get the Console features (e.g. password hiding) kicking in.

    private static String readLine(String prompt) {
String line = null;
Console c = System.console();
if (c != null) {
line = c.readLine(prompt);
} else {
System.out.print(prompt);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
try {
line = bufferedReader.readLine();
} catch (IOException e) {
//Ignore
}
}
return line;
}

You can implement a class yourself. Following is an example:

public class Console {
BufferedReader br;
PrintStream ps;


public Console(){
br = new BufferedReader(new InputStreamReader(System.in));
ps = System.out;
}


public String readLine(String out){
ps.format(out);
try{
return br.readLine();
}catch(IOException e)
{
return null;
}
}
public PrintStream format(String format, Object...objects){
return ps.format(format, objects);
}
}

Let's say your Eclipse workspace is C:\MyWorkspace, you created your java application inside a maven project MyProject, and your Java main class is com.mydomain.mypackage.MyClass.

In this case, you can run your main class that uses System.console() on the command line:

java -cp C:\MyWorkspace\MyProject\target\classes com.mydomain.mypackage.MyClass

NB1: if it's not in a maven project, check the output folder in project properties | Java Build Path | Source. It might not be "target/classes"

NB2: if it is a maven project, but your class is in src/test/java, you'll likely have to use "target\test-classes" instead of "target\classes"