8039137: KSS: JTextComponent.isProcessInputMethodEventOverridden
Reviewed-by: alexsch, serb
--- a/jdk/src/share/classes/com/sun/beans/util/Cache.java Fri Apr 04 20:12:41 2014 +0400
+++ b/jdk/src/share/classes/com/sun/beans/util/Cache.java Fri Apr 04 20:18:53 2014 +0400
@@ -119,13 +119,13 @@
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) {
--- a/jdk/src/share/classes/javax/swing/text/JTextComponent.java Fri Apr 04 20:12:41 2014 +0400
+++ b/jdk/src/share/classes/javax/swing/text/JTextComponent.java Fri Apr 04 20:18:53 2014 +0400
@@ -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.*;
@@ -1194,47 +1192,6 @@
}
/**
- * 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 @@
* 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,39 +4924,16 @@
*/
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
//
boolean composedTextExists() {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/beans/Introspector/TestCacheRecursion.java Fri Apr 04 20:18:53 2014 +0400
@@ -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 {}
+}