8039137: KSS: JTextComponent.isProcessInputMethodEventOverridden

Reviewed-by: alexsch, serb
This commit is contained in:
Sergey Malenkov 2014-04-04 20:18:53 +04:00
parent b04364a90e
commit 002763f0fc
3 changed files with 117 additions and 74 deletions

View File

@ -119,13 +119,13 @@ public abstract class Cache<K,V> {
synchronized (this.queue) {
// synchronized search improves stability
// we must create and add new value if there are no needed entry
int index = index(hash, this.table);
current = getEntryValue(key, hash, this.table[index]);
current = getEntryValue(key, hash, this.table[index(hash, this.table)]);
if (current != null) {
return current;
}
V value = create(key);
Objects.requireNonNull(value, "value");
int index = index(hash, this.table);
this.table[index] = new CacheEntry<>(hash, key, value, this.table[index]);
if (++this.size >= this.threshold) {
if (this.table.length == MAXIMUM_CAPACITY) {

View File

@ -24,18 +24,16 @@
*/
package javax.swing.text;
import java.lang.reflect.Method;
import com.sun.beans.util.Cache;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.beans.Transient;
import java.util.Collections;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Enumeration;
import java.util.Vector;
import java.util.Map;
import java.util.concurrent.*;
@ -1193,47 +1191,6 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A
}
}
/**
* Returns true if <code>klass</code> is NOT a JTextComponent and it or
* one of its superclasses (stoping at JTextComponent) overrides
* <code>processInputMethodEvent</code>. It is assumed this will be
* invoked from within a <code>doPrivileged</code>, and it is also
* assumed <code>klass</code> extends <code>JTextComponent</code>.
*/
private static Boolean isProcessInputMethodEventOverridden(Class<?> klass) {
if (klass == JTextComponent.class) {
return Boolean.FALSE;
}
Boolean retValue = overrideMap.get(klass.getName());
if (retValue != null) {
return retValue;
}
Boolean sOverriden = isProcessInputMethodEventOverridden(
klass.getSuperclass());
if (sOverriden.booleanValue()) {
// If our superclass has overriden it, then by definition klass
// overrides it.
overrideMap.put(klass.getName(), sOverriden);
return sOverriden;
}
// klass's superclass didn't override it, check for an override in
// klass.
try {
Class[] classes = new Class[1];
classes[0] = InputMethodEvent.class;
Method m = klass.getDeclaredMethod("processInputMethodEvent",
classes);
retValue = Boolean.TRUE;
} catch (NoSuchMethodException nsme) {
retValue = Boolean.FALSE;
}
overrideMap.put(klass.getName(), retValue);
return retValue;
}
/**
* Fetches the current color used to render the
* caret.
@ -3916,7 +3873,33 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A
* Maps from class name to Boolean indicating if
* <code>processInputMethodEvent</code> has been overriden.
*/
private static Map<String, Boolean> overrideMap;
private static Cache<Class<?>,Boolean> METHOD_OVERRIDDEN
= new Cache<Class<?>,Boolean>(Cache.Kind.WEAK, Cache.Kind.STRONG) {
/**
* Returns {@code true} if the specified {@code type} extends {@link JTextComponent}
* and the {@link JTextComponent#processInputMethodEvent} method is overridden.
*/
@Override
public Boolean create(final Class<?> type) {
if (JTextComponent.class == type) {
return Boolean.FALSE;
}
if (get(type.getSuperclass())) {
return Boolean.TRUE;
}
return AccessController.doPrivileged(
new PrivilegedAction<Boolean>() {
public Boolean run() {
try {
type.getDeclaredMethod("processInputMethodEvent", InputMethodEvent.class);
return Boolean.TRUE;
} catch (NoSuchMethodException exception) {
return Boolean.FALSE;
}
}
});
}
};
/**
* Returns a string representation of this <code>JTextComponent</code>.
@ -4941,38 +4924,15 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A
*/
private boolean shouldSynthensizeKeyEvents() {
if (!checkedInputOverride) {
// Checks whether the client code overrides processInputMethodEvent.
// If it is overridden, need not to generate KeyTyped events for committed text.
// If it's not, behave as an passive input method client.
needToSendKeyTypedEvent = !METHOD_OVERRIDDEN.get(getClass());
checkedInputOverride = true;
needToSendKeyTypedEvent =
!isProcessInputMethodEventOverridden();
}
return needToSendKeyTypedEvent;
}
//
// Checks whether the client code overrides processInputMethodEvent. If it is overridden,
// need not to generate KeyTyped events for committed text. If it's not, behave as an
// passive input method client.
//
private boolean isProcessInputMethodEventOverridden() {
if (overrideMap == null) {
overrideMap = Collections.synchronizedMap(new HashMap<String, Boolean>());
}
Boolean retValue = overrideMap.get(getClass().getName());
if (retValue != null) {
return retValue.booleanValue();
}
Boolean ret = AccessController.doPrivileged(new
PrivilegedAction<Boolean>() {
public Boolean run() {
return isProcessInputMethodEventOverridden(
JTextComponent.this.getClass());
}
});
return ret.booleanValue();
}
//
// Checks whether a composed text in this text component
//

View File

@ -0,0 +1,83 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import com.sun.beans.util.Cache;
/*
* @test
* @bug 8039137
* @summary Tests Cache recursion
* @author Sergey Malenkov
* @compile -XDignore.symbol.file TestCacheRecursion.java
* @run main TestCacheRecursion
*/
public class TestCacheRecursion {
private static boolean ERROR;
private static final Cache<Class<?>,Boolean> CACHE
= new Cache<Class<?>,Boolean>(Cache.Kind.WEAK, Cache.Kind.STRONG) {
@Override
public Boolean create(Class<?> type) {
if (ERROR) {
throw new Error("not initialized");
}
type = type.getSuperclass();
return (type != null) && get(type);
}
};
public static void main(String[] args) {
CACHE.get(Z.class);
ERROR = true;
for (Class<?> type = Z.class; type != null; type = type.getSuperclass()) {
CACHE.get(type);
}
}
private class A {}
private class B extends A {}
private class C extends B {}
private class D extends C {}
private class E extends D {}
private class F extends E {}
private class G extends F {}
private class H extends G {}
private class I extends H {}
private class J extends I {}
private class K extends J {}
private class L extends K {}
private class M extends L {}
private class N extends M {}
private class O extends N {}
private class P extends O {}
private class Q extends P {}
private class R extends Q {}
private class S extends R {}
private class T extends S {}
private class U extends T {}
private class V extends U {}
private class W extends V {}
private class X extends W {}
private class Y extends X {}
private class Z extends Y {}
}