Suporte java.io.Console no IDE Eclipse

103

Eu uso o Eclipse IDE para desenvolver, compilar e executar meus projetos Java. Hoje, estou tentando usar a java.io.Consoleclasse para gerenciar a saída e, mais importante, a entrada do usuário.

O problema é que System.console()retorna nullquando um aplicativo é executado "por meio" do Eclipse. O Eclipse executa o programa em um processo de segundo plano, em vez de um processo de nível superior com a janela do console com a qual estamos familiarizados.

Existe uma maneira de forçar o Eclipse a executar o programa como um processo de nível superior ou, pelo menos, criar um Console que o JVM reconhecerá? Caso contrário, sou forçado a sacudir o projeto e executá-lo em um ambiente de linha de comando externo ao Eclipse.

Ross
fonte
Consulte também stackoverflow.com/questions/26470972/… Eu identifiquei System.oute System.inpara ser suficiente para meu caso de uso e abandonei o uso System.console().
OneWorld
Exportei o projeto como o jar executável, mas ainda estou recebendo o erro nulo do console
Abhigyan

Respostas:

50

Presumo que você queira usar a depuração passo a passo do Eclipse. Você pode simplesmente executar as classes externamente, definindo as classes construídas nos diretórios bin no caminho de classe JRE.

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

Você pode depurar usando o depurador remoto e aproveitando as vantagens dos arquivos de classe construídos em seu projeto.

Neste exemplo, a estrutura do projeto Eclipse se parece com isto:

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

1. Inicie o console JVM no modo de depuração

debug.bat é um arquivo em lote do Windows que deve ser executado externamente a partir de um console cmd.exe .

@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

Nos argumentos, a porta de depuração foi definida como 8787 . O argumento suspend = y diz à JVM para esperar até que o depurador seja conectado.

2. Crie uma configuração de inicialização de depuração

No Eclipse, abra a caixa de diálogo Debug (Run> Open Debug Dialog ...) e crie uma nova configuração de aplicativo Java remoto com as seguintes configurações:

  • Projeto: o nome do seu projeto
  • Tipo de conexão: Padrão (conexão de soquete)
  • Host: localhost
  • Porta: 8787

3. Depuração

Portanto, tudo o que você precisa fazer sempre que quiser depurar o aplicativo é:

  • definir um ponto de interrupção
  • lançar o arquivo em lote em um console
  • iniciar a configuração de depuração

Você pode rastrear esse problema no bug 122429 . Você pode contornar esse problema em seu aplicativo usando uma camada de abstração conforme descrito aqui .

McDowell
fonte
1
Eu também colocaria um pauseno final desse arquivo em lote para que você possa ver todas as mensagens de erro que aparecem antes de fechar.
Matt Lyons,
10
Esta é a gota d'água para mim. Se eu tiver que fazer tudo isso apenas para depurar, estou voltando para o Netbeans. Tantos bugs não corrigidos e aborrecimentos da interface do usuário no Eclipse que nem chega a ser engraçado.
nuzzolilo
@Nuzzolilo, isso é apenas para depuração remota. Você pode depurar localmente no eclipse sem tudo isso.
Laplie Anderson
35

A solução alternativa que eu uso é apenas usar System.in/System.out em vez de Console ao usar o Eclipse. Por exemplo, em vez de:

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

Você pode usar:

BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
String line = bufferedReader.readLine();
Laplie Anderson
fonte
20
Eu não acho que você seria capaz de ler senhas com mascaramento de senha dessa forma.
Sualeh Fatehi
3
... e uma necessidade de manusear IOException, que não é lançada no caso de Console.readLine().
dma_k
5

Isso ocorre porque o eclipse executa seu aplicativo como um processo em segundo plano e não como um processo de nível superior com um console do sistema.

Heath Borders
fonte
5

Você mesmo pode implementar uma classe. A seguir está um exemplo:

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);
    }
}
yztaoj
fonte
4

Encontrei algo sobre isso em http://www.stupidjavatricks.com/?p=43 .

E, infelizmente, como o console é definitivo, você não pode estendê-lo para criar um wrapper em torno de system.in e system.out que faça isso também. Mesmo dentro do console do Eclipse, você ainda tem acesso a eles. É provavelmente por isso que o eclipse ainda não conectou isso ao console deles ...

Eu entendo por que você não gostaria de ter outra maneira de obter um console diferente de System.console, sem setter, mas não entendo por que você não gostaria que alguém pudesse substituir a classe para fazer um simulado / console de teste ...

John Gardner
fonte
4

Outra opção é criar um método para encerrar ambas as opções e "failover" para o método System.in quando o Console não estiver disponível. O exemplo abaixo é bastante básico - você pode seguir o mesmo processo para agrupar os outros métodos no Console (readPassword, format) conforme necessário. Dessa forma, você pode executá-lo alegremente no Eclipse e quando ele for implantado, você terá os recursos do console (por exemplo, ocultar senha) ativados.

    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;
    }
cubo binário
fonte
2

Pelo que eu posso dizer, não há como obter um objeto Console do Eclipse. Eu apenas me certificaria de que o console! = Null, então JAR e executaria a partir da linha de comando.

perimosocordiae
fonte
1

Parece não haver maneira de obter um objeto java.io.Console ao executar um aplicativo por meio do Eclipse. Uma janela de console de linha de comando não é aberta com o aplicativo, pois ele é executado como um processo de segundo plano (segundo plano para o Eclipse?). Atualmente, não existe um plugin do Eclipse para lidar com este problema, principalmente devido ao fato de que java.io.Console é uma classe final.

Tudo o que você realmente pode fazer é testar o objeto Console retornado para null e prosseguir a partir daí.

Ross
fonte
1

Este link oferece alternativas para usar System.console (). Uma é usar um BufferedReader envolvido em System.in, a segunda é usar um Scanner em System.in.

Nenhum deles é tão conciso quanto o console, mas ambos funcionam em eclipse sem ter que recorrer a bobagens de depuração!

Dave Richardson
fonte
0

Digamos que seu espaço de trabalho do Eclipse seja C: \ MyWorkspace, você criou seu aplicativo java dentro de um projeto maven MyProject e sua classe principal Java é com.mydomain.mypackage.MyClass.

Nesse caso, você pode executar sua classe principal que usa System.console()na linha de comando:

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

NB1: se não estiver em um projeto maven, verifique a pasta de saída nas propriedades do projeto | Caminho de construção Java | Fonte. Pode não ser "alvo / classes"

NB2: se for um projeto maven, mas sua classe está em src / test / java, você provavelmente terá que usar "target \ test-classes" em vez de "target \ classes"

Paulo Merson
fonte