Jaskaranbir Singh
Jaskaranbir Singh

Reputation: 2034

java overriding getText method on textField while manipulating textField data

I have created an external class that overrides JTextField. In the class I have added a DocumentListener which replaces prevents a certain character from being entered. Below is code (its not exact code, for purpose of simplicity of this question):

import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

class test extends JTextField{
private String filteredText;

public void getDefaultText(){
super.getText();
}

public String getText(){
return filteredText;
}

public void remword(){
super.getDocument().addDocumentListener(new DocumentListener() {

            @Override
            public void changedUpdate(DocumentEvent arg0) {
            }

            @Override
            public void insertUpdate(DocumentEvent arg0) {
                Runnable ru = new Runnable() {
                    @Override
                    public void run() {
                                String finalText = getDefaultText().replace("xyz", "asd");
                                setText(finalText);
                                filteredText = finalText;
                        }
                    }
                };
                SwingUtilities.invokeLater(ru);         
}

            @Override
            public void removeUpdate(DocumentEvent arg0) {
            }
});
}
}

Now this code works fine unless I use the getText() method which returns error Attempt to mutate in notificaton. I have tried messing around with synchronized and Runnable to no avail.

Upvotes: 0

Views: 392

Answers (1)

xehpuk
xehpuk

Reputation: 8241

From DocumentListener:

The DocumentEvent notification is based upon the JavaBeans event model. There is no guarantee about the order of delivery to listeners, and all listeners must be notified prior to making further mutations to the Document. This means implementations of the DocumentListener may not mutate the source of the event (i.e. the associated Document).

You should use a DocumentFilter for control over document manipulation.

By the way, using getText() shouldn't throw this exception. You probably meant setText(String).

You don't need to subclass JTextField for this use case:

((AbstractDocument) textField.getDocument()).setDocumentFilter(new DocumentFilter() {
    @Override
    public void insertString(DocumentFilter.FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException {
        super.insertString(fb, offset, sanitize(string), attr);
    }

    @Override
    public void replace(DocumentFilter.FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
        super.replace(fb, offset, length, sanitize(text), attrs);
    }

    private String sanitize(String s) {
        return s == null ? null : s.replace("xyz", "asd");
    }
});

Beware that my solution would still allow "xyz" in the document if entered letter by letter or by removing e.g. "_" from "xy_z".

Upvotes: 3

Related Questions