8133453: Deprecate AWTKeyStroke.registerSubclass(Class) method
Reviewed-by: serb, azvegint
--- a/jdk/src/java.desktop/share/classes/java/awt/AWTKeyStroke.java Tue Sep 22 12:26:50 2015 +0300
+++ b/jdk/src/java.desktop/share/classes/java/awt/AWTKeyStroke.java Tue Sep 22 14:05:37 2015 +0400
@@ -32,12 +32,9 @@
import java.util.Map;
import java.util.StringTokenizer;
import java.io.Serializable;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.lang.reflect.Field;
+import sun.swing.SwingAccessor;
/**
* An <code>AWTKeyStroke</code> represents a key action on the
@@ -80,21 +77,6 @@
//A key withing the cache
private static AWTKeyStroke APP_CONTEXT_KEYSTROKE_KEY = new AWTKeyStroke();
- /*
- * Reads keystroke class from AppContext and if null, puts there the
- * AWTKeyStroke class.
- * Must be called under locked AWTKeyStroke
- */
- private static Class<AWTKeyStroke> getAWTKeyStrokeClass() {
- @SuppressWarnings("unchecked")
- Class<AWTKeyStroke> clazz = (Class<AWTKeyStroke>)AppContext.getAppContext().get(AWTKeyStroke.class);
- if (clazz == null) {
- clazz = AWTKeyStroke.class;
- AppContext.getAppContext().put(AWTKeyStroke.class, AWTKeyStroke.class);
- }
- return clazz;
- }
-
private char keyChar = KeyEvent.CHAR_UNDEFINED;
private int keyCode = KeyEvent.VK_UNDEFINED;
private int modifiers;
@@ -160,92 +142,15 @@
}
/**
- * Registers a new class which the factory methods in
- * <code>AWTKeyStroke</code> will use when generating new
- * instances of <code>AWTKeyStroke</code>s. After invoking this
- * method, the factory methods will return instances of the specified
- * Class. The specified Class must be either <code>AWTKeyStroke</code>
- * or derived from <code>AWTKeyStroke</code>, and it must have a
- * no-arg constructor. The constructor can be of any accessibility,
- * including <code>private</code>. This operation
- * flushes the current <code>AWTKeyStroke</code> cache.
+ * The method has no effect and is only left present to avoid introducing
+ * a binary incompatibility.
*
* @param subclass the new Class of which the factory methods should create
* instances
- * @throws IllegalArgumentException if subclass is <code>null</code>,
- * or if subclass does not have a no-arg constructor
- * @throws ClassCastException if subclass is not
- * <code>AWTKeyStroke</code>, or a class derived from
- * <code>AWTKeyStroke</code>
+ * @deprecated
*/
+ @Deprecated
protected static void registerSubclass(Class<?> subclass) {
- if (subclass == null) {
- throw new IllegalArgumentException("subclass cannot be null");
- }
- synchronized (AWTKeyStroke.class) {
- @SuppressWarnings("unchecked")
- Class<AWTKeyStroke> keyStrokeClass = (Class)AppContext.getAppContext().get(AWTKeyStroke.class);
- if (keyStrokeClass != null && keyStrokeClass.equals(subclass)){
- // Already registered
- return;
- }
- }
- if (!AWTKeyStroke.class.isAssignableFrom(subclass)) {
- throw new ClassCastException("subclass is not derived from AWTKeyStroke");
- }
-
- Constructor<?> ctor = getCtor(subclass);
-
- String couldNotInstantiate = "subclass could not be instantiated";
-
- if (ctor == null) {
- throw new IllegalArgumentException(couldNotInstantiate);
- }
- try {
- AWTKeyStroke stroke = (AWTKeyStroke)ctor.newInstance((Object[]) null);
- if (stroke == null) {
- throw new IllegalArgumentException(couldNotInstantiate);
- }
- } catch (NoSuchMethodError e) {
- throw new IllegalArgumentException(couldNotInstantiate);
- } catch (ExceptionInInitializerError e) {
- throw new IllegalArgumentException(couldNotInstantiate);
- } catch (InstantiationException e) {
- throw new IllegalArgumentException(couldNotInstantiate);
- } catch (IllegalAccessException e) {
- throw new IllegalArgumentException(couldNotInstantiate);
- } catch (InvocationTargetException e) {
- throw new IllegalArgumentException(couldNotInstantiate);
- }
-
- synchronized (AWTKeyStroke.class) {
- AppContext.getAppContext().put(AWTKeyStroke.class, subclass);
- AppContext.getAppContext().remove(APP_CONTEXT_CACHE_KEY);
- AppContext.getAppContext().remove(APP_CONTEXT_KEYSTROKE_KEY);
- }
- }
-
- /* returns no-arg Constructor for class with accessible flag. No security
- threat as accessible flag is set only for this Constructor object,
- not for Class constructor.
- */
- private static Constructor<?> getCtor(final Class<?> clazz)
- {
- Constructor<?> ctor = AccessController.doPrivileged(new PrivilegedAction<Constructor<?>>() {
- public Constructor<?> run() {
- try {
- Constructor<?> ctor = clazz.getDeclaredConstructor((Class<?>[]) null);
- if (ctor != null) {
- ctor.setAccessible(true);
- }
- return ctor;
- } catch (SecurityException e) {
- } catch (NoSuchMethodException e) {
- }
- return null;
- }
- });
- return ctor;
}
private static synchronized AWTKeyStroke getCachedStroke
@@ -261,18 +166,10 @@
}
if (cacheKey == null) {
- try {
- Class<AWTKeyStroke> clazz = getAWTKeyStrokeClass();
- cacheKey = (AWTKeyStroke)getCtor(clazz).newInstance((Object[]) null);
- AppContext.getAppContext().put(APP_CONTEXT_KEYSTROKE_KEY, cacheKey);
- } catch (InstantiationException e) {
- assert(false);
- } catch (IllegalAccessException e) {
- assert(false);
- } catch (InvocationTargetException e) {
- assert(false);
- }
+ cacheKey = SwingAccessor.getKeyStrokeAccessor().create();
+ AppContext.getAppContext().put(APP_CONTEXT_KEYSTROKE_KEY, cacheKey);
}
+
cacheKey.keyChar = keyChar;
cacheKey.keyCode = keyCode;
cacheKey.modifiers = mapNewModifiers(mapOldModifiers(modifiers));
@@ -806,11 +703,9 @@
*/
protected Object readResolve() throws java.io.ObjectStreamException {
synchronized (AWTKeyStroke.class) {
- if (getClass().equals(getAWTKeyStrokeClass())) {
- return getCachedStroke(keyChar, keyCode, modifiers, onKeyRelease);
- }
+
+ return getCachedStroke(keyChar, keyCode, modifiers, onKeyRelease);
}
- return this;
}
private static int mapOldModifiers(int modifiers) {
--- a/jdk/src/java.desktop/share/classes/javax/swing/KeyStroke.java Tue Sep 22 12:26:50 2015 +0300
+++ b/jdk/src/java.desktop/share/classes/javax/swing/KeyStroke.java Tue Sep 22 14:05:37 2015 +0400
@@ -26,6 +26,7 @@
import java.awt.AWTKeyStroke;
import java.awt.event.KeyEvent;
+import sun.swing.SwingAccessor;
/**
* A KeyStroke represents a key action on the keyboard, or equivalent input
@@ -70,6 +71,16 @@
*/
private static final long serialVersionUID = -9060180771037902530L;
+ static {
+ SwingAccessor.setKeyStrokeAccessor(new SwingAccessor.KeyStrokeAccessor() {
+
+ @Override
+ public KeyStroke create() {
+ return new KeyStroke();
+ }
+ });
+ }
+
private KeyStroke() {
}
private KeyStroke(char keyChar, int keyCode, int modifiers,
@@ -87,7 +98,6 @@
*/
public static KeyStroke getKeyStroke(char keyChar) {
synchronized (AWTKeyStroke.class) {
- registerSubclass(KeyStroke.class);
return (KeyStroke)getAWTKeyStroke(keyChar);
}
}
@@ -148,7 +158,6 @@
*/
public static KeyStroke getKeyStroke(Character keyChar, int modifiers) {
synchronized (AWTKeyStroke.class) {
- registerSubclass(KeyStroke.class);
return (KeyStroke)getAWTKeyStroke(keyChar, modifiers);
}
}
@@ -199,7 +208,6 @@
public static KeyStroke getKeyStroke(int keyCode, int modifiers,
boolean onKeyRelease) {
synchronized (AWTKeyStroke.class) {
- registerSubclass(KeyStroke.class);
return (KeyStroke)getAWTKeyStroke(keyCode, modifiers,
onKeyRelease);
}
@@ -247,7 +255,6 @@
*/
public static KeyStroke getKeyStroke(int keyCode, int modifiers) {
synchronized (AWTKeyStroke.class) {
- registerSubclass(KeyStroke.class);
return (KeyStroke)getAWTKeyStroke(keyCode, modifiers);
}
}
@@ -266,7 +273,6 @@
*/
public static KeyStroke getKeyStrokeForEvent(KeyEvent anEvent) {
synchronized (AWTKeyStroke.class) {
- registerSubclass(KeyStroke.class);
return (KeyStroke)getAWTKeyStrokeForEvent(anEvent);
}
}
@@ -307,7 +313,6 @@
return null;
}
synchronized (AWTKeyStroke.class) {
- registerSubclass(KeyStroke.class);
try {
return (KeyStroke)getAWTKeyStroke(s);
} catch (IllegalArgumentException e) {
--- a/jdk/src/java.desktop/share/classes/sun/swing/SwingAccessor.java Tue Sep 22 12:26:50 2015 +0300
+++ b/jdk/src/java.desktop/share/classes/sun/swing/SwingAccessor.java Tue Sep 22 14:05:37 2015 +0400
@@ -97,6 +97,14 @@
int ownerX, int ownerY);
}
+ /*
+ * An accessor for the KeyStroke class
+ */
+ public interface KeyStrokeAccessor {
+
+ KeyStroke create();
+ }
+
/**
* The javax.swing.text.JTextComponent class accessor object.
*/
@@ -185,4 +193,26 @@
public static void setPopupFactoryAccessor(PopupFactoryAccessor popupFactoryAccessor) {
SwingAccessor.popupFactoryAccessor = popupFactoryAccessor;
}
+
+ /**
+ * The KeyStroke class accessor object.
+ */
+ private static KeyStrokeAccessor keyStrokeAccessor;
+
+ /**
+ * Retrieve the accessor object for the KeyStroke class.
+ */
+ public static KeyStrokeAccessor getKeyStrokeAccessor() {
+ if (keyStrokeAccessor == null) {
+ unsafe.ensureClassInitialized(KeyStroke.class);
+ }
+ return keyStrokeAccessor;
+ }
+
+ /*
+ * Set the accessor object for the KeyStroke class.
+ */
+ public static void setKeyStrokeAccessor(KeyStrokeAccessor accessor) {
+ SwingAccessor.keyStrokeAccessor = accessor;
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/event/KeyEvent/RegisterKeyStroke/TestAWTKeyStroke.java Tue Sep 22 14:05:37 2015 +0400
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2015, 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 java.awt.AWTKeyStroke;
+import java.awt.event.InputEvent;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInput;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+import javax.swing.KeyStroke;
+
+/*
+ * @test
+ * @bug 8133453
+ * @summary Remove AWTKeyStroke.registerSubclass(Class) method
+ * @author Alexander Scherbatiy
+ * @run main/othervm TestAWTKeyStroke
+ * @run main/othervm/policy=policy -Djava.security.manager TestAWTKeyStroke
+ */
+public class TestAWTKeyStroke {
+
+ public static void main(String[] args) throws Exception {
+
+ int modifiers = InputEvent.CTRL_MASK | InputEvent.CTRL_DOWN_MASK;
+ checkAWTKeyStroke('A', modifiers, true);
+ checkKeyStroke('B', modifiers, false);
+ checkAWTKeyStroke('C', modifiers, false);
+ checkKeyStroke('D', modifiers, true);
+ checkSerializedKeyStrokes('E', modifiers, true);
+ }
+
+ private static void checkAWTKeyStroke(int keyCode, int modifiers,
+ boolean onKeyRelease) throws Exception {
+
+ AWTKeyStroke awtKeyStroke1 = AWTKeyStroke.getAWTKeyStroke(
+ keyCode, modifiers, onKeyRelease);
+
+ checkAWTKeyStroke(awtKeyStroke1, keyCode, modifiers, onKeyRelease);
+
+ AWTKeyStroke awtKeyStroke2 = AWTKeyStroke.getAWTKeyStroke(
+ keyCode, modifiers, onKeyRelease);
+
+ if (awtKeyStroke1 != awtKeyStroke2) {
+ throw new RuntimeException("AWTKeyStroke is not cached!");
+ }
+
+ checkSerializedKeyStroke(awtKeyStroke1);
+ }
+
+ private static void checkKeyStroke(int keyCode, int modifiers,
+ boolean onKeyRelease) throws Exception {
+
+ KeyStroke keyStroke1 = KeyStroke.getKeyStroke(
+ keyCode, modifiers, onKeyRelease);
+ checkAWTKeyStroke(keyStroke1, keyCode, modifiers, onKeyRelease);
+
+ KeyStroke keyStroke2 = KeyStroke.getKeyStroke(
+ keyCode, modifiers, onKeyRelease);
+
+ if (keyStroke1 != keyStroke2) {
+ throw new RuntimeException("KeyStroke is not cached!");
+ }
+
+ checkSerializedKeyStroke(keyStroke1);
+ }
+
+ private static void checkSerializedKeyStrokes(int keyCode, int modifiers,
+ boolean onKeyRelease) throws Exception {
+
+ AWTKeyStroke awtKeyStroke = AWTKeyStroke.getAWTKeyStroke(
+ keyCode, modifiers, onKeyRelease);
+
+ KeyStroke keyStroke = KeyStroke.getKeyStroke(
+ keyCode, modifiers, onKeyRelease);
+
+ if (awtKeyStroke != getSerializedAWTKeyStroke(awtKeyStroke)) {
+ throw new RuntimeException("Serialized AWTKeyStroke is not cached!");
+ }
+
+ awtKeyStroke = AWTKeyStroke.getAWTKeyStroke(
+ keyCode, modifiers, !onKeyRelease);
+
+ if (!keyStroke.equals(getSerializedAWTKeyStroke(keyStroke))) {
+ throw new RuntimeException("Serialized KeyStroke is not cached!");
+ }
+ }
+
+ private static void checkAWTKeyStroke(AWTKeyStroke awtKeyStroke,
+ int keyCode, int modifiers, boolean onKeyRelease) {
+
+ if (awtKeyStroke.getKeyCode() != keyCode) {
+ throw new RuntimeException("Wrong key code!");
+ }
+
+ if (awtKeyStroke.getModifiers() != modifiers) {
+ throw new RuntimeException("Wrong modifiers!");
+ }
+
+ if (awtKeyStroke.isOnKeyRelease() != onKeyRelease) {
+ throw new RuntimeException("Wrong on key release!");
+ }
+ }
+
+ private static void checkSerializedKeyStroke(AWTKeyStroke keyStroke)
+ throws Exception {
+ if (keyStroke != getSerializedAWTKeyStroke(keyStroke)) {
+ throw new RuntimeException("New instance is returned during"
+ + " serialization!");
+ }
+ }
+
+ private static AWTKeyStroke getSerializedAWTKeyStroke(AWTKeyStroke keyStroke)
+ throws Exception {
+
+ try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ ObjectOutput out = new ObjectOutputStream(bos)) {
+ out.writeObject(keyStroke);
+ byte[] bytes = bos.toByteArray();
+
+ try (ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
+ ObjectInput in = new ObjectInputStream(bis)) {
+ return (AWTKeyStroke) in.readObject();
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/event/KeyEvent/RegisterKeyStroke/policy Tue Sep 22 14:05:37 2015 +0400
@@ -0,0 +1,2 @@
+grant {
+};