Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8335587

TextInputControl: Binding prompt text that contains linebreak causes exception

    XMLWordPrintable

Details

    • generic
    • generic

    Description

      ADDITIONAL SYSTEM INFORMATION :
      Should occur on all systems and with all recent OpenJFX versions.

      Tested with:

      Win10
      openjdk 17.0.1


      Linux asl754 5.14.0-362.13.1.el9_3.x86_64 #1 SMP PREEMPT_DYNAMIC Wed Dec 13 14:07:45 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
      openjdk 17.0.9 2023-10-17 LTS
      OpenJDK Runtime Environment (Red_Hat-17.0.9.0.9-1) (build 17.0.9+9-LTS)
      OpenJDK 64-Bit Server VM (Red_Hat-17.0.9.0.9-1) (build 17.0.9+9-LTS, mixed mode, sharing)

      A DESCRIPTION OF THE PROBLEM :
      When binding the promptTextProperty of a TextInputControl (TextField or TextArea) to a text that contains linebreaks/newlines ("\n"), the "bind" call causes a RuntimeException to be thrown.

      This is due to special handling in "TextInputControl.promptText.invalidated" that strips out newlines.
      https://github.com/openjdk/jfx/blob/ca04c87d307c36591162af8cd6298ede17812834/modules/javafx.controls/src/main/java/javafx/scene/control/TextInputControl.java#L323

      java.lang.RuntimeException: TextArea.promptText : A bound value cannot be set.
      at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:141) // throws when observable is set
      at javafx.scene.control.TextInputControl$3.invalidated(TextInputControl.java:286) // strips out newlines, calls .set
      at javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:110)
      at javafx.beans.property.StringPropertyBase.bind(StringPropertyBase.java:172) // stores the observable

      The exceptions is only triggered when binding the prompt text (setting is fine), and when the text contains newlines (text without newlines can be bound without any problem).

      (Sidenote: I question whether stripping out the newlines makes sense for the multi-line TextArea, but I will create a separate issue for this.)

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Bind the promptTextProperty of a TextInputControl (TextField or TextArea) to a text that contains linebreaks/newlines ("\n").

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      The prompt text is bound to the specified text (possibly with stripped newlines).
      ACTUAL -
      RuntimeException, e.g.
      Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: TextField.promptText : A bound value cannot be set.


      ---------- BEGIN SOURCE ----------
      package bugdemos;

      import javafx.application.Application;
      import javafx.beans.property.SimpleStringProperty;
      import javafx.beans.property.StringProperty;
      import javafx.scene.control.TextArea;
      import javafx.scene.control.TextField;
      import javafx.scene.control.TextInputControl;
      import javafx.stage.Stage;

      public class BoundPromptWithLineBreaksBugSimpleDemoApp extends Application {

          private static final String PROMPT_NO_LINEBREAKS = "Prompt w/o linebreaks";

          private static final String PROMPT_WITH_LINEBREAKS = "Prompt" + "\n" + "with" + "\n" + "linebreaks";

          public static void main(final String[] args) {
              launch(args);
          }

          @Override
          public void start(final Stage stage) throws Exception {
              final TextField textField = new TextField();

              final TextArea textArea = new TextArea();

              final StringProperty promptProperty = new SimpleStringProperty();

              System.out.println("\n---Setting a prompt without linebreaks: OK for both textfield and textarea");
              setPromptAndReadBack(textField, PROMPT_NO_LINEBREAKS);
              setPromptAndReadBack(textArea, PROMPT_NO_LINEBREAKS);

              System.out.println(
                      "\n---Setting a prompt with linebreaks: OK for both textfield and textarea, linebreaks are stripped");
              setPromptAndReadBack(textField, PROMPT_WITH_LINEBREAKS);
              setPromptAndReadBack(textArea, PROMPT_WITH_LINEBREAKS);

              System.out.println("\n---Binding a prompt without linebreaks: OK for both textfield and textarea");
              bindPromptAndReadBack(textField, promptProperty, PROMPT_NO_LINEBREAKS);
              bindPromptAndReadBack(textArea, promptProperty, PROMPT_NO_LINEBREAKS);

              System.out.println(
                      "\n---Binding a prompt with linebreaks: BROKEN for both textfield and textarea, causes exceptions");
              bindPromptAndReadBack(textField, promptProperty, PROMPT_WITH_LINEBREAKS);
              bindPromptAndReadBack(textArea, promptProperty, PROMPT_WITH_LINEBREAKS);

              System.exit(0);
          }

          private static void setPromptAndReadBack(final TextInputControl textInput, final String prompt) {
              textInput.setPromptText(prompt);

              System.out.println(
                      textInput.getClass().getSimpleName() //
                              + " SET: \"" + prompt + "\" READ BACK: \"" + textInput.getPromptText() + "\"");
          }

          private static void bindPromptAndReadBack(
                  final TextInputControl textInput,
                  final StringProperty promptProperty,
                  final String prompt) {
              textInput.promptTextProperty().unbind();

              promptProperty.setValue(prompt);

              try {
                  textInput.promptTextProperty().bind(promptProperty);

                  System.out.println(textInput.getClass().getSimpleName() + //
                          " BOUND TO: \"" + prompt + "\" READ BACK: \"" + textInput.getPromptText() + "\"");
              } catch (final RuntimeException ex) {
                  // Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: TextField.promptText : A bound value cannot be set.
                  // Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: TextArea.promptText : A bound value cannot be set.
                  System.err.println(
                          textInput.getClass().getSimpleName() //
                                  + " Failed to bind prompt \"" + prompt + "\"");
                  ex.printStackTrace();
              } finally {

                  // undo binding for next test
                  textInput.promptTextProperty().unbind();
              }
          }

      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      None that allows newlines in bound prompt texts.

      Option A: Remove newlines
      Option B: Do not use prompt text, use normal text property instead

      FREQUENCY : always


      Attachments

        Issue Links

          Activity

            People

              angorya Andy Goryachev
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

                Created:
                Updated: