From 002763f0fca956ecd65253fbb3bdb595f7757341 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Fri, 4 Apr 2014 20:18:53 +0400 Subject: [PATCH] 8039137: KSS: JTextComponent.isProcessInputMethodEventOverridden Reviewed-by: alexsch, serb --- .../classes/com/sun/beans/util/Cache.java | 4 +- .../javax/swing/text/JTextComponent.java | 104 ++++++------------ .../Introspector/TestCacheRecursion.java | 83 ++++++++++++++ 3 files changed, 117 insertions(+), 74 deletions(-) create mode 100644 jdk/test/java/beans/Introspector/TestCacheRecursion.java diff --git a/jdk/src/share/classes/com/sun/beans/util/Cache.java b/jdk/src/share/classes/com/sun/beans/util/Cache.java index 4f3f75571b0..2cb21791416 100644 --- a/jdk/src/share/classes/com/sun/beans/util/Cache.java +++ b/jdk/src/share/classes/com/sun/beans/util/Cache.java @@ -119,13 +119,13 @@ public abstract class Cache { 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) { diff --git a/jdk/src/share/classes/javax/swing/text/JTextComponent.java b/jdk/src/share/classes/javax/swing/text/JTextComponent.java index 714b3381619..94f950eb88b 100644 --- a/jdk/src/share/classes/javax/swing/text/JTextComponent.java +++ b/jdk/src/share/classes/javax/swing/text/JTextComponent.java @@ -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 klass is NOT a JTextComponent and it or - * one of its superclasses (stoping at JTextComponent) overrides - * processInputMethodEvent. It is assumed this will be - * invoked from within a doPrivileged, and it is also - * assumed klass extends JTextComponent. - */ - 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 * processInputMethodEvent has been overriden. */ - private static Map overrideMap; + private static Cache,Boolean> METHOD_OVERRIDDEN + = new Cache,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() { + public Boolean run() { + try { + type.getDeclaredMethod("processInputMethodEvent", InputMethodEvent.class); + return Boolean.TRUE; + } catch (NoSuchMethodException exception) { + return Boolean.FALSE; + } + } + }); + } + }; /** * Returns a string representation of this JTextComponent. @@ -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()); - } - Boolean retValue = overrideMap.get(getClass().getName()); - - if (retValue != null) { - return retValue.booleanValue(); - } - Boolean ret = AccessController.doPrivileged(new - PrivilegedAction() { - public Boolean run() { - return isProcessInputMethodEventOverridden( - JTextComponent.this.getClass()); - } - }); - - return ret.booleanValue(); - } - // // Checks whether a composed text in this text component // diff --git a/jdk/test/java/beans/Introspector/TestCacheRecursion.java b/jdk/test/java/beans/Introspector/TestCacheRecursion.java new file mode 100644 index 00000000000..cb36deccb92 --- /dev/null +++ b/jdk/test/java/beans/Introspector/TestCacheRecursion.java @@ -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,Boolean> CACHE + = new Cache,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 {} +}