8133453: Deprecate AWTKeyStroke.registerSubclass(Class) method
authoralexsch
Tue, 22 Sep 2015 14:05:37 +0400
changeset 32867 90051b1c4e3d
parent 32866 234e264e9265
child 32868 8ca464bbfbae
8133453: Deprecate AWTKeyStroke.registerSubclass(Class) method Reviewed-by: serb, azvegint
jdk/src/java.desktop/share/classes/java/awt/AWTKeyStroke.java
jdk/src/java.desktop/share/classes/javax/swing/KeyStroke.java
jdk/src/java.desktop/share/classes/sun/swing/SwingAccessor.java
jdk/test/java/awt/event/KeyEvent/RegisterKeyStroke/TestAWTKeyStroke.java
jdk/test/java/awt/event/KeyEvent/RegisterKeyStroke/policy
--- 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 {
+};