Obsługa java.io.Console w Eclipse IDE

103

Używam środowiska Eclipse IDE do opracowywania, kompilowania i uruchamiania projektów w języku Java. Dzisiaj próbuję użyć tej java.io.Consoleklasy do zarządzania danymi wyjściowymi i, co ważniejsze, danymi wejściowymi użytkownika.

Problem polega na tym, że System.console()powraca, nullgdy aplikacja jest uruchamiana „przez” Eclipse. Eclipse uruchamia program w procesie w tle, a nie w procesie najwyższego poziomu w znanym nam oknie konsoli.

Czy istnieje sposób, aby zmusić Eclipse do uruchomienia programu jako procesu najwyższego poziomu lub przynajmniej utworzyć konsolę, którą rozpozna JVM? W przeciwnym razie jestem zmuszony zepsuć projekt i uruchomić go w środowisku wiersza poleceń zewnętrznym w stosunku do Eclipse.

Ross
źródło
Zobacz także stackoverflow.com/questions/26470972/ ... Zidentyfikowałem System.outi System.injako wystarczające dla mojego przypadku użycia i zrezygnowałem z używania System.console().
OneWorld
Wyeksportowałem projekt jako działający plik jar, ale nadal otrzymuję błąd konsoli o wartości NULL
Abhigyan

Odpowiedzi:

50

Zakładam, że chcesz mieć możliwość debugowania krok po kroku z Eclipse. Możesz po prostu uruchamiać klasy zewnętrznie, ustawiając zbudowane klasy w katalogach bin w ścieżce klas JRE.

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

Możesz debugować za pomocą zdalnego debugera i korzystając z plików klas wbudowanych w projekcie.

W tym przykładzie struktura projektu Eclipse wygląda następująco:

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

1. Uruchom konsolę JVM w trybie debugowania

debug.bat to plik wsadowy systemu Windows, który powinien być uruchamiany zewnętrznie z konsoli 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

W argumentach port debugowania został ustawiony na 8787 . Argument suspend = y informuje maszynę JVM, aby poczekała, aż debugger się podłączy.

2. Utwórz konfigurację uruchamiania debugowania

W Eclipse otwórz okno dialogowe Debugowanie (Uruchom> Otwórz okno dialogowe debugowania ...) i utwórz nową konfigurację zdalnej aplikacji Java z następującymi ustawieniami:

  • Projekt: nazwa twojego projektu
  • Typ połączenia: standardowe (podłączenie do gniazda)
  • Host: localhost
  • Port: 8787

3. Debugowanie

Tak więc wszystko, co musisz zrobić za każdym razem, gdy chcesz debugować aplikację, to:

  • ustawić punkt przerwania
  • uruchom plik wsadowy w konsoli
  • uruchom konfigurację debugowania

Możesz śledzić ten problem w błędzie 122429 . Możesz obejść ten problem w swojej aplikacji, używając warstwy abstrakcji, jak opisano tutaj .

McDowell
źródło
1
Umieściłbym również pausena końcu tego pliku wsadowego, abyś mógł zobaczyć wszelkie komunikaty o błędach, które migają przed zamknięciem.
Matt Lyons,
10
To dla mnie ostatnia kropla. Jeśli muszę to wszystko zrobić tylko po to, by debugować, wracam do Netbeans. Tak wiele nie naprawionych błędów i niedogodności interfejsu użytkownika w Eclipse, że nie jest to nawet śmieszne.
nuzzolilo
@Nuzzolilo, to jest tylko do zdalnego debugowania. Możesz debugować lokalnie w eclipse bez tego wszystkiego.
Laplie Anderson
35

Obejście, którego używam, to po prostu użycie System.in/System.out zamiast Console podczas korzystania z Eclipse. Na przykład zamiast:

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

Możesz użyć:

BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
String line = bufferedReader.readLine();
Laplie Anderson
źródło
20
Nie sądzę, że byłbyś w stanie odczytać hasła z maskowaniem hasła w ten sposób.
Sualeh Fatehi
3
... i trzeba sobie poradzić IOException, czego w przypadku nie wyrzucamy Console.readLine().
dma_k,
5

Dzieje się tak, ponieważ eclipse uruchamia aplikację jako proces w tle, a nie jako proces najwyższego poziomu z konsolą systemową.

Heath Borders
źródło
5

Możesz samodzielnie wdrożyć klasę. Oto przykład:

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
źródło
4

Znalazłem coś na ten temat pod adresem http://www.stupidjavatricks.com/?p=43 .

I niestety, ponieważ konsola jest ostateczna, nie możesz jej rozszerzyć, aby utworzyć opakowanie wokół system.in i system.out, które też to robi. Nawet w konsoli Eclipse nadal masz do nich dostęp. Prawdopodobnie dlatego Eclipse nie podłączyło tego jeszcze do swojej konsoli ...

Rozumiem, dlaczego nie chciałbyś mieć innego sposobu na uzyskanie konsoli innej niż Konsola System.console, bez setera, ale nie rozumiem, dlaczego nie chciałbyś, aby ktoś mógł zastąpić klasę, aby utworzyć makieta / konsola testowa ...

John Gardner
źródło
4

Inną opcją jest utworzenie metody umożliwiającej zawinięcie obu opcji i „przełączenie awaryjne” na metodę System.in, gdy konsola nie jest dostępna. Poniższy przykład jest dość podstawowy - możesz wykonać ten sam proces, aby zawrzeć inne metody w konsoli (readPassword, format) zgodnie z wymaganiami. W ten sposób możesz go szczęśliwie uruchomić w Eclipse, a po jego wdrożeniu pojawią się funkcje konsoli (np. Ukrywanie hasła).

    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;
    }
binarycube
źródło
2

O ile wiem, nie ma sposobu na uzyskanie obiektu Console z Eclipse. Po prostu upewniłbym się, że konsola! = Null, a następnie JAR ją i uruchomię z wiersza poleceń.

perimosocordiae
źródło
1

Wydaje się, że nie ma możliwości uzyskania obiektu java.io.Console podczas uruchamiania aplikacji za pośrednictwem Eclipse. Okno konsoli wiersza poleceń nie jest otwierane z aplikacją, ponieważ jest ona uruchamiana jako proces w tle (tło do Eclipse?). Obecnie nie ma wtyczki Eclipse do obsługi tego problemu, głównie ze względu na fakt, że java.io.Console jest ostatnią klasą.

Wszystko, co naprawdę możesz zrobić, to przetestować zwrócony obiekt Console pod kątem wartości null i przejść dalej.

Ross
źródło
1

Ten link oferuje alternatywy dla korzystania z System.console (). Jednym z nich jest użycie BufferedReader owiniętego wokół System.in, a drugim jest użycie skanera owiniętego wokół System.in.

Żadne z nich nie są tak zwięzłe jak konsola, ale oba działają w zaćmieniu bez konieczności uciekania się do debugowania głupoty!

Dave Richardson
źródło
0

Załóżmy, że Twój obszar roboczy Eclipse to C: \ MyWorkspace, aplikacja Java została utworzona w projekcie maven MyProject, a Twoja główna klasa Java to com.mydomain.mypackage.MyClass.

W takim przypadku możesz uruchomić swoją główną klasę, która używa System.console()w linii poleceń:

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

NB1: jeśli nie jest w projekcie maven, sprawdź folder wyjściowy we właściwościach projektu | Ścieżka budowania Java | Źródło. To może nie być „cel / klasy”

NB2: jeśli jest to projekt maven, ale twoja klasa znajduje się w src / test / java, prawdopodobnie będziesz musiał użyć „target \ test-classes” zamiast „target \ classes”

Paulo Merson
źródło