8 Replies Latest reply: Jan 13, 2011 10:57 AM by doremifasollatido RSS

    Using System.setIn to Change the InputStream

    830874
      Hi All

      I am trying to change my System.in InputStream to instead take values from the terminal window but take values from a JEditorPane or JTextBox.

      I have this to add the text to the new InputStream which has been declared.
      Code:
      GUI Class:
      public static InputStream consoleInputStream;
      ...
      sendButton.addActionListener(new ActionListener() {
           public void actionPerformed(ActionEvent e) {
                String message = sendPane.getText();
                consoleInputStream = new ByteArrayInputStream(message.getBytes());
                sendPane.setText("");
           }
      });
      I then want to use this in another class to output the text:
      Code:
      System.setIn(GUI.consoleInputStream);
      ...
      public static String readLine() {
           String s = null;
           BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
           try {
                s = in.readLine();
           } catch (IOException e) {
                e.printStackTrace();
           }
           return s;
      }
      But I get java.lang.NullPointerException at java.io.Reader. (Unknown Source) at java.io.InputStreamReader. (Unknown Source).

      What I have is a CLI applciation that runs off the User inputs from the terminal within Eclipse all I want to do is change main System.in input Stream to a Jtextbox output. I have the above working just in CLI (of course not setting System.setIn()...)

      Any pointers would be awsome!
        • 1. Re: Using System.setIn to Change the InputStream
          800330
          If CLI code is yours too, try the reverse approach: make the CLI work off some InputStream parameter that you initialize with System.in for CLI mode, and with your GUI provided InputStream otherwise.
          • 2. Re: Using System.setIn to Change the InputStream
            830874
            The CLI is mine too and works fine if I do not use the GUI.

            I know if i run the CLI with the GUI i can set the teh System.in to another Input Stream but I can't seem to create that input stream on to be used.

            I want to take the submitted input from a JText box or something similar and place it in the Input Stream that then can be picked up by the InputStream (/System.in) being read on the CLI. Its creating that InputStream where I get stuck :(
            • 3. Re: Using System.setIn to Change the InputStream
              800330
              I did understand your problem the first time around, dont worry.

              I'd like to suggest, not to change System.in but instead have the CLI not refer to System.in directly, but initialize an InputStream member to System.in on start-up.

              Doing so allows you to write some tests (junit-tests...) with pre-cooked input that you put in via a ByteArrayInputStream or a StringReader.

              For your problem, perhaps the input from the GUI does not contain a new line? But that should be easy enough to confirm writing again a little bit of test code that verifies only the input handling.
              • 4. Re: Using System.setIn to Change the InputStream
                830874
                Changing my readLine() method to take input from another InputStream would not be any issue.

                IIf I do
                     
                     InputStream consoleInputStream = new ByteArrayInputStream(message.getBytes());
                     BufferedReader in = new BufferedReader(new InputStreamReader(consoleInputStream ));
                     try {
                          System.out.println(in.readLine());
                     } catch (IOException e) {
                          e.printStackTrace();
                     }
                It all works fine its as soon as I move teh BufferReader part out of that method and class when I get the issue and that doesn't make sence to me since its being given the same input!
                • 5. Re: Using System.setIn to Change the InputStream
                  800330
                  I will now admit that I did not read your code or question very carefully the first time around. I was triggered by assigning to System.in, which is valid to do, but a code-smell to do. I think it is better to write the program to read from some input (stream) that may or may not be System.in.

                  Your reply confuses me, you have the GUI input now working?

                  In any case, the snippets of code you posted are a bit unusual as it suggests to construct a new BufferedReader for every line that is read. I don't think that is how things are supposed to work. Typically, you'd have one BufferedReader from which you take a line at a time until it does not have more lines. I am sorry if am not helping you very much at this point.
                  • 6. Re: Using System.setIn to Change the InputStream
                    830874
                    My previous code snippet works if I just use the GUI class with that all in the same method. However when I move the BufferReader out into another method or class it fails and throws null pointer exceptions.

                    I have tried to place my BufferReader in another method and class both using System.setIn(other input) and BufferReader.....(other input) with no difference still throws null pointer exceptions.
                    • 7. Re: Using System.setIn to Change the InputStream
                      800330
                      Here's my attempt to get to a small program that would come near to your problem. The idea being bring the problem down in size, such that you understand all of it. If the smaller stuff works, incorporate it in the big. Can you make your program small enough to post here, while it still has the problem?
                      package otn;
                      
                      import java.awt.BorderLayout;
                      import java.awt.Dimension;
                      import java.awt.event.ActionEvent;
                      import java.awt.event.ActionListener;
                      import java.io.BufferedReader;
                      import java.io.ByteArrayOutputStream;
                      import java.io.IOException;
                      import java.io.InputStreamReader;
                      import java.io.PrintStream;
                      import java.io.StringReader;
                      
                      import javax.swing.JFrame;
                      import javax.swing.JPanel;
                      import javax.swing.JTextArea;
                      import javax.swing.JTextField;
                      import javax.swing.SwingUtilities;
                      
                      public class Capitalizer {
                      
                           void handleOneLine(String text, PrintStream out) {
                                out.println(text.toUpperCase());
                           }
                           
                           void work(BufferedReader in, PrintStream out) throws IOException {
                                String s = null;
                                while ((s = in.readLine()) != null) {
                                     handleOneLine(s, out);
                                }
                           }
                           
                          public void createGui() {
                               final JTextArea outputArea = new JTextArea();
                               final JTextField input = new JTextField();
                               JPanel pane = new JPanel();
                               pane.setLayout(new BorderLayout());
                              pane.setPreferredSize(new Dimension(400, 400));
                              pane.add(outputArea, BorderLayout.CENTER);
                              pane.add(input, BorderLayout.SOUTH);
                       
                              JFrame frame = new JFrame("Example");
                              frame.add(pane);
                              frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                              frame.pack();
                              frame.setVisible(true);
                              
                              input.addActionListener(new ActionListener() {
                                     @Override
                                     public void actionPerformed(ActionEvent e) {
                                          String text = input.getText();
                                          input.setText("");
                                          ByteArrayOutputStream b = new ByteArrayOutputStream();
                                          try {
                                               work(new BufferedReader(new StringReader(text)), new PrintStream(b));
                                               outputArea.append(b.toString());
                                          } catch (IOException ioe) {
                                               //ignored
                                          }
                                          
                                          
                                     }
                                });
                          }
                           
                           
                           public static void main(String[] args) throws IOException {
                                boolean cli = false;
                                if (cli) {
                                     new Capitalizer().work(new BufferedReader(new InputStreamReader(System.in)), System.out);
                                } else {
                                   SwingUtilities.invokeLater(new Runnable() {
                                          @Override
                                          public void run() {
                                               new Capitalizer().createGui();
                                          }
                                     });
                                }
                           }
                      }
                      • 8. Re: Using System.setIn to Change the InputStream
                        doremifasollatido
                        user13723191 wrote:
                        I then want to use this in another class to output the text:
                        Code:
                        System.setIn(GUI.consoleInputStream);
                        ...
                        public static String readLine() {
                             String s = null;
                             BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
                             try {
                                  s = in.readLine();
                             } catch (IOException e) {
                                  e.printStackTrace();
                             }
                             return s;
                        }
                        But I get java.lang.NullPointerException at java.io.Reader. (Unknown Source) at java.io.InputStreamReader. (Unknown Source).
                        Calling System.setIn once at the beginning of your program (before the button is pressed) will not let you automatically see updates to GUI.consoleInputStream. If you call setIn before the button is pressed to set GUI.consoleInputStream to a non-null value, then System.in is permanently null. You will need to call System.setIn(GUI.consoleInputStream) every time you push button and make a new stream.

                        Using isocdev_mb's suggestion to let the CLI use an InputStream instead of using System.in directly might work. Or, instead of a constant InputStream provided at initialization, maybe the initialization of the CLI could require an instance of a class that implements an interface allowing you to retrieve the appropriate InputStream every time you need access to it. Then, when using the CLI alone, you could pass something that just uses System.in (this could be an anonymous class that implements the interface). When using the GUI, you could pass something that returns the current value of GUI.consoleInputStream (this allows GUI.consoleInputStream to keep changing, while the CLI always gets the current value, without calling System.setIn multiple times).