Java – Getting ‘Attempt to mutate notification’ exception
My goal is to implement blue coloring of keywords written by user into JTextPane. This is how my code look like:
private class DocumentHandler implements DocumentListener < @Override public void changedUpdate(DocumentEvent ev) < >@Override public void insertUpdate(DocumentEvent ev) < highlight(); >@Override public void removeUpdate(DocumentEvent ev) < highlight(); >private void highlight() < String code = codePane.getText(); SimpleAttributeSet defSet = new SimpleAttributeSet(); StyleConstants.setForeground(defSet, Color.BLACK); doc.setCharacterAttributes(0, code.length(), defSet, true); SimpleAttributeSet set = new SimpleAttributeSet(); StyleConstants.setForeground(set, Color.BLUE); for (String keyword : keywords) < Pattern pattern = Pattern.compile(keyword + "(\\[\\])*"); Matcher matcher = pattern.matcher(code); while (matcher.find()) < //Just for test System.out.print("Start index: " + matcher.start()); System.out.print(" End index: " + matcher.end()); System.out.println(" Found: " + matcher.group()); doc.setCharacterAttributes(matcher.start(), keyword.length(), set, true); >> > >
After typing anything into pane I get:
Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Attempt to mutate in notification at javax.swing.text.AbstractDocument.writeLock(AbstractDocument.java:1338) at javax.swing.text.DefaultStyledDocument.setCharacterAttributes(DefaultStyledDocument.java:500) at jnotepad.MainPanel$DocumentHandler.highlight(MainPanel.java:121) at jnotepad.MainPanel$DocumentHandler.insertUpdate(MainPanel.java:108) at javax.swing.text.AbstractDocument.fireInsertUpdate(AbstractDocument.java:202) at javax.swing.text.AbstractDocument.handleInsertString(AbstractDocument.java:749)
How to solve my problem? Maybe I should use something other than DocumentListener?
Best Solution
You need to invoke changes to the document from the Event Dispatcher Thread.
private void highlight() < Runnable doHighlight = new Runnable() < @Override public void run() < // your highlight code >>; SwingUtilities.invokeLater(doHighlight); >
Getting ‘Attempt to mutate notification’ exception
You need to invoke changes to the document from the Event Dispatcher Thread.
private void highlight() < Runnable doHighlight = new Runnable() < @Override public void run() < // your highlight code >>; SwingUtilities.invokeLater(doHighlight); >
Solution 2
I had the same problem, I solved it by using this:
expiration_timeTF.getDocument().addDocumentListener( new DocumentListener() < @Override public void removeUpdate(DocumentEvent e) < System.out.println("remove"); >private void assistDateText() < Runnable doAssist = new Runnable() < @Override public void run() < // when input "2013",will add to "2013-";when // input "2013-10",will add to "2013-10-" String input = expiration_timeTF.getText(); if (input.matches("^1")) < expiration_timeTF.setText(input + "-"); >else if (input.matches("^7-3")) < expiration_timeTF.setText(input + "-"); >> >; SwingUtilities.invokeLater(doAssist); > @Override public void insertUpdate(DocumentEvent e) < // System.out.println("insert"); assistDateText(); >@Override public void changedUpdate(DocumentEvent e) < // System.out.println("change"); >>);
user2102972
Comments
My goal is to implement blue coloring of keywords written by user into JTextPane. This is how my code look like:
private class DocumentHandler implements DocumentListener < @Override public void changedUpdate(DocumentEvent ev) < >@Override public void insertUpdate(DocumentEvent ev) < highlight(); >@Override public void removeUpdate(DocumentEvent ev) < highlight(); >private void highlight() < String code = codePane.getText(); SimpleAttributeSet defSet = new SimpleAttributeSet(); StyleConstants.setForeground(defSet, Color.BLACK); doc.setCharacterAttributes(0, code.length(), defSet, true); SimpleAttributeSet set = new SimpleAttributeSet(); StyleConstants.setForeground(set, Color.BLUE); for (String keyword : keywords) < Pattern pattern = Pattern.compile(keyword + "(\\[\\])*"); Matcher matcher = pattern.matcher(code); while (matcher.find()) < //Just for test System.out.print("Start index: " + matcher.start()); System.out.print(" End index: " + matcher.end()); System.out.println(" Found: " + matcher.group()); doc.setCharacterAttributes(matcher.start(), keyword.length(), set, true); >> > >
Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Attempt to mutate in notification at javax.swing.text.AbstractDocument.writeLock(AbstractDocument.java:1338) at javax.swing.text.DefaultStyledDocument.setCharacterAttributes(DefaultStyledDocument.java:500) at jnotepad.MainPanel$DocumentHandler.highlight(MainPanel.java:121) at jnotepad.MainPanel$DocumentHandler.insertUpdate(MainPanel.java:108) at javax.swing.text.AbstractDocument.fireInsertUpdate(AbstractDocument.java:202) at javax.swing.text.AbstractDocument.handleInsertString(AbstractDocument.java:749)
Issue is not that highlight() is executing from wrong thread. Rather, invokeLater(Runnable) fixes problem because it postpones execution until Document lock is released.
@MoritzSchmidt, unlucky scheduling should never occur. Queued EDT tasks run to completion before successors are processed.
@HollisWaite Thats nice to know. Thank you. But the solution still looks like a hack to me.. Or is this really the cleanest solution?
@MoritzSchmidt, I’m no expert on JTextPane internals. I think that’s the most elegant solution but I could be wrong. Regardless, if you’re building a moderately complex Swing application, you’ll inevitably find yourself leveraging the ‘invokeLater’ idiom. In this particular case, the cleanest option is to use some third-party library (e.g. JSyntaxPane).
altering a GUI object without triggering the listener
posted 13 years ago
In my program there are some GUI items (a JTable for example) which have Listener objects to listen for changes to the item’s content when the content is changed by the program user. Then when the content is changed, it fires an event and that causes the program to update the content of the GUI by changing the content. However, of course when the program changes something, I don’t want the GUI to react to that event. So what I do is I have a boolean called something like byuser and set it to true most of the time, and before the program changes the GUI, it sets byuser to false, and after it changes the GUI, it sets byuser to true again. And in the method called when the event is fired, I put a line which checks whether or not byuser is true, and does something only if byuser is true.
Anyway, that is how I do it. But I have a feeling that that is not the standard way to do it. What is the standard way of having a GUI object react to the user, but not to the program?
posted 13 years ago
To be more specific about my question, I have a JTextField that has autocomplete function that I am trying to write. When I typed something in the JTextField, the program tried to change the text too and I got this message:
java.lang.IllegalStateException: Attempt to mutate in notification
What’s that?
posted 13 years ago
Kevin Tysen wrote: When I typed something in the JTextField, the program tried to change the text too
Perhaps you should just show the suggestions and not immediately change the input.
Anyhow, the best would be to share your code (a snip) with us .
Marshal
posted 13 years ago
posted 13 years ago
When the user clicks on an item in cList, that item is passed as a String to setInputText(String newText). userTextChange is set to false. Then .setText(String text) is called, which causes 2 events. The first event is removeUpdate(DocumentEvent e), and nothing happens, and the second event is insertUpdate(DocumentEvent e). When that is called, nothing happens because userTextChange is false. After that, userTextChange is set to true again.
When the user types something in input (the JTextField), insertUpdate(DocumentEvent e) is called, and because userTextChange is true, the findIndex() method is called, which chooses the index of a String from cList. Then cList scrolls to show the String. Then cList.setSelectedIndex(int index) is called. Here is where the problem is.
I expect the program-initiated selection of cList to trigger the valueChanged(ListSelectionEvent lse) event, which calls setInputText(String newText). Then userTextChange is changed to false, then the text is changed, but now that userTextChange is false, when removeUpdate and insertUpdate events occur, nothing happens.
That is what I expect, but I get an Exception which I described above arising in the setInputText(String newText) method.
Maybe what I need is a better way to change the text in input without causing the insertUpdate event.
posted 13 years ago
you type something into the textfield, and during insertUpdate() you change the selected index of the list.
this change to the list triggers the listSelectionListener, which tries to set the text of the textfield,
so it errors because you’re trying to change the text while it is still being modified (insertUpdate).
these few lines should fix it
add this as a class field
cLListener listListener = new cLListener();
change this
//cList.addListSelectionListener(new cLListener());
cList.addListSelectionListener(listListener);
add the two indicated lines in autoCompleteListener
cList.removeListSelectionListener(listListener);// cList.ensureIndexIsVisible(mLSIndex);
cList.setSelectedIndex(mLSIndex);
cList.addListSelectionListener(listListener);//
posted 13 years ago
Removing the ListSelectionListener will keep my program from getting an Exception. However, I WANT the ListSelectionListener to change the text in the JTextField. The problem is (according to the printStackTrace) that when the Listener tries to change the text in the JTextField, it calls writeLock() method in the AbstractDocument object in the JTextField, which causes IllegalStateException because the writeLock is not available (probably because the cursor is still in the JTextField and it is in the middle of being edited by the user).
The API of AbstractDocument has this explanation for the IllegalStateException thrown by the writeLock method:
«thrown on illegal lock attempt. If the document is implemented properly, this can only happen if a document listener attempts to mutate the document. This situation violates the bean event model where order of delivery is not guaranteed and all listeners should be notified before further mutations are allowed»
In my program, a document listener IS attempting to mutate the document (but indirectly).
So I think that my next step is to find a way to release the key in the AbstractDocument object so that the program can edit its text.
I know that when I click on an item in the JList, there is no problem. So I think that if the focus is off the JTextField, the key will be released. So I added the line
cList.requestFocus();
just before the setSelectedIndex(mLSIndex) line. I figured that if cList gets focused on, the user editing of the JTextField will come to an end and the key will be released. But that didn’t work. I still got the same IllegalStateException.
java.lang.IllegalStateException ??
posted 22 years ago
Hello All,
I have a serious problem in my code which I could not able to fix. Here is the message «java.lang.IllegalStateException: Attempt to mutate in notification». Ok, my code is using a preparestatement and document listener event to verify a user input field, I have no problem to verify the field. My application has another function that allow the user to find specify record ( for example: input a value then return a result in table with all match crteria, and then user can click the «LOCK» to lock the selected row to update, if the result contains an invlid value, the error message appears, however, if the result value are correct, the program is happy.
I hope you can understand my problem. I am not explaning it very well, sorry.
Thanks a lot.
Mindy
«The Hood»
posted 22 years ago
Apparently you are attempting to modify the contents of the document before notification is complete. Is your stuff synchronized?
From the API for AbstractDocument
This class implements a locking mechanism for the document. It allows multiple readers or one writer, and writers must wait until all observers of the document have been notified of a previous change before beginning another mutation to the document. The read lock is aquired and released using the render method. A write lock is aquired by the methods that mutate the document, and are held for the duration of the method call
Notification is done on the thread that produced the mutation,
and the thread has full read access to the document for the duration of the notification, but other readers are kept out until the notification has finished. The notification
is a beans event notification which does not allow any further mutations until all listeners have been notified.
«JavaRanch, where the deer and the Certified play» — David O’Meara