JDK-6480545 : InputVerifier behavior change in 1.5+
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 5.0
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2006-10-11
  • Updated: 2014-10-26
  • Resolved: 2011-03-08
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 Availabitlity Release.

To download the current JDK release, click here.
6u2Fixed 7 b07Fixed
Related Reports
Relates :  
java version "1.5.0_09"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_09-b01)
Java HotSpot(TM) Client VM (build 1.5.0_09-b01, mixed mode)

Microsoft Windows XP [Version 5.1.2600]

The behavior of the InputVerifier has dramatically chagned in version 1.5+ which precludes two (or more) JComponents from having active InputVerifiers in the same JVM.

We have JComponets which use an InputVerifier to invoke a JDialog to assist the user in further qualifying bad entries.  These JDialogs in turn have JComponents which also use different InputVerifiers.  Since 1.5 the subsequent (nested) InputVerifiers have stopped working.

This bug can be reproduced always.

Found the following code in JComponent 1.5:
    private boolean runInputVerifier() {
        if (inInputVerifier) {
            // We're already running the InputVerifier, assume the
            // developer knows what they're doing.
            return true;

By commenting out the conditional test of "inInputVerifier", the original behavior returns.
Because "inInputVerifier" is a private variable, it cannot be over-ridden by an descendant class.  Also because it is static, all JComponents across the JVM are limited.
Because method "runInputVerifer()" is private, it cannot be over-ridden by an ancestor class.

EVALUATION On thinking about this more, it seems probable that folks are relying on changing focus in the same window from the InputVerifier. As such, it's worth keeping this logic around, without the hacky invokeLater. The fix is to move from the static field inInputVerifier to an AppContext value. The AppContext value identifies the component the InputVerifier is running for. If we're in the code where we attempt to run the InputVerifier, and the AppContext value identifies the same component, we now we're in a loop, and don't notify the InputVerifier again. To deal with the case of showing a modal dialog, with it's own InputVerifier, and after the modal dialog is hidden trasfering focus, the AppContext value is treated like a stack. That is, after the InputVerifier has run, rather than setting the AppContext value to null, it's set to the last value contained in the AppContext. This enables avoiding loops when InputVerifiers are run from within InputVerifiers.

EVALUATION This regression resulted from 4532517, which centered around a limitation of the InputVerifier. Prior to the fix for 4532517 developers could not (unless they did the work around) show an option pane from an InputVerifier. This happened because we would get stuck in an infinite loop showing the option pane; focus continually kept trying to get taken from the button, which triggered IV to run, which triggered another dialog ... The fix for 4532517 was to remember if we were calling into the InputVerifier, and if so, don't call into it until the call returns. Roughly: static boolean inInputVerifier; inInputVerifier = true; callInputVerifier(); inInputVerifier = false; This resulted in the regression 6480545. The problem with the fix is that if you show a modal dialog that also has an InputVerifier, we'll still be blocked in callInputVerifier and inInputVerifier will be true so that the InputVerifier attached to a child of the modal dialog never gets run. This is intimately related to 6401036 (and 6378278). When fixing 6401036 we came to the conclusion that the InputVerifier shouldn't be notified when focus changes occur across windows. As such, it seems to me the fix for 4532517 is no longer needed, and can be backed out. The one case where 4532517 is still needed, is if for some reason the InputVerifier wanted to change focus within the same window. This seems like an odd case. Given the current fix, I can't say if folks are relying on this working now (it would). The only way I could seem accommodating this desire along with 6480545 is to do something like: inInputVerifier = true; SwingUtilities.invokeLater(new Runnable() { public void run() { inInputVerifier = false; } }); callInputVerifier(); inInputVerifier = false; YUCK! I'm inclined to back out 4532517, and be done with it. If folks want the odd behavior of changing focus in the IV to some where in the same window, they should be responsible for toggling VerifyInputWhenFocusTarget.

EVALUATION Received test case from customer (attached). Will futher evaluate shortly.

EVALUATION This was introduced as a result of fixing 4532517. The fix seems good to me, but I need a test case to verify that. Contacting submitter for more info.