JDK-6355666 : REGRESSION: NullPointerException occurs in getCommittedTextLength method when IME is ON
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 5.0u4
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2005-11-28
  • Updated: 2010-12-03
  • Resolved: 2006-01-04
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other JDK 6
5.0u8Fixed 6 b66Fixed
Description
synopsis:    NullPointerException occurs in getCommittedTextLength method
description: While the switch of Input Method Editor (IME) is ON, when some key is pressed, NullPointerException occurs each time.

It occurs on J2SE 5.0_04, but it does not occur on J2SE 1.4.2.

- STEPS TO FOLLOW TO REPRODUCE THE PROBLEM:

E:\xiaojun\support\JTextField>java TextFieldTest 
-----
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
 at javax.swing.text.JTextComponent$InputMethodRequestsHandler.getCommittedTextLength(Unknown Source)
 at CustomTextField.isCommittedText(TextFieldTest.java:46)
 at CustomTextField.access$0(TextFieldTest.java:44)
 at CustomTextField$CustomDocumentAdapter.insertUpdate(TextFieldTest.java:54)
 at javax.swing.text.AbstractDocument.fireInsertUpdate(Unknown Source)
 at javax.swing.text.AbstractDocument.handleInsertString(Unknown Source)
 at javax.swing.text.AbstractDocument.insertString(Unknown Source)
 at javax.swing.text.PlainDocument.insertString(Unknown Source)
 at javax.swing.text.JTextComponent.replaceInputMethodText(Unknown Source)
 at javax.swing.text.JTextComponent.processInputMethodEvent(Unknown Source)
 at java.awt.Component.processEvent(Unknown Source)
 at java.awt.Container.processEvent(Unknown Source)
 at java.awt.Component.dispatchEventImpl(Unknown Source)
 at java.awt.Container.dispatchEventImpl(Unknown Source)
 at java.awt.Component.dispatchEvent(Unknown Source)
 at java.awt.EventQueue.dispatchEvent(Unknown Source)
 at java.awt.EventDispatchThread.pumpOneEventForHierarchy(Unknown Source)
 at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
 at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
 at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
 at java.awt.EventDispatchThread.run(Unknown Source)
-----

I guess that getCommittedTextLength method has been modified
in relation to BugID.5004088.

As indicated by the last of [Evaluation] of this bug report,
the idea of 'Position for the end of composedText' has been introduced from tiger-beta2 for BugID.5004088.
And so, I guess that the implementation of getCommittedTextLength method has been changed according to the position.

[BugID:5004088 REGRESSION: Delete composed text caused insertion of erroneous text]
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5004088

As the present inner implementation of JTextComponent,
the position of ComposedText is determined after the event which notifies that the character has been inserted to the document is issued.

------JTextComponent SOURCE--------------------------
3579 doc.insertString(caret.getDot(), composedTextContent,
3580     composedTextAttribute);
3581 composedTextStart = doc.createPosition(caret.getDot() -
3582    composedTextContent.length());
3583    composedTextEnd = doc.createPosition(caret.getDot());
-----------------------------------------------------

When DocumentListener#insertUpdate was call-backed by the event,
the position of ComposedText has not been determined yet.

Consequently, when getCommittedTextLength method is invoked in
DocumentListener#insertUpdate,
I guess that NullPointerException occurs in the process of using the position of ComposedText in getCommittedTextLength method.

- EXPECTED VERSUS ACTUAL BEHAVIOR:

NullPoiterException does not occur like J2SE 1.4.2.

- REPRODUCIBILITY:

The following source code issues always NullPointerException
when some key is pressed, while the switch of IME is ON.

---------- BEGIN SOURCE ----------
import java.awt.im.InputMethodRequests;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

public class TextFieldTest extends JFrame {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new TextFieldTest();
            }
        });
    }

    public TextFieldTest() {
        this.init();
        this.setSize(150, 60);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }

    private void init() {
        CustomTextField textField = new CustomTextField();
        textField.setColumns(10);

        JPanel panel = new JPanel();
        panel.add(textField);

        this.getContentPane().add(panel);
    }
}

class CustomTextField extends JTextField {

    public CustomTextField() {
        getDocument().addDocumentListener(new CustomDocumentAdapter());
    }

    private boolean isCommittedText() {
        InputMethodRequests imr = getInputMethodRequests();
        int committedTextLength = imr.getCommittedTextLength();
        int textLength = getText().length();
        return committedTextLength == textLength;
    }

    private class CustomDocumentAdapter implements DocumentListener {
        public void insertUpdate(DocumentEvent e) {
            System.out.println("insert");
            isCommittedText();
        }

        public void removeUpdate(DocumentEvent e) {
            System.out.println("remove");
            isCommittedText();
        }

        public void changedUpdate(DocumentEvent e) {
            System.out.println("change");
            isCommittedText();
        }
    }
}

Comments
EVALUATION The only time when composedTextContent is not null and composedTextEnd or composedTextStart are nulls is after createComposedTextAttribute(composedTextIndex, text); and before composedTextStart and composedTextEnd are initialized. doc.insertString(caret.getDot(), composedTextContent, composedTextAttribute); happens in this time frame and thus DocumentListener is invoked when composedTextStart and composedTextEnd are nulls. Because of that getCommittedTextLength throws NullPointerException in this line: length -= composedTextEnd.getOffset() - composedTextStart.getOffset(); I suggest to address this problme in getCommittedTextLength method. *** /tmp/geta17256 Wed Nov 30 18:15:43 2005 --- JTextComponent.java Wed Nov 30 17:26:00 2005 *************** *** 4493,4500 **** if (doc != null) { length = doc.getLength(); if (composedTextContent != null) { ! length -= composedTextEnd.getOffset() - ! composedTextStart.getOffset(); } } return length; --- 4493,4512 ---- if (doc != null) { length = doc.getLength(); if (composedTextContent != null) { ! if (composedTextEnd == null ! || composedTextStart == null) { ! /* ! * fix for : 6355666 ! * this is the case when this method is invoked ! * from DocumentListener. At this point ! * composedTextEnd and composedTextStart are ! * not defined yet. ! */ ! length -= composedTextContent.length(); ! } else { ! length -= composedTextEnd.getOffset() - ! composedTextStart.getOffset(); ! } } } return length;
30-11-2005

EVALUATION NullPointerException is indeed thrown becuase of the fix for 5004088.
30-11-2005