8133453: Deprecate AWTKeyStroke.registerSubclass(Class) method

Reviewed-by: serb, azvegint
This commit is contained in:
Alexander Scherbatiy 2015-09-22 14:05:37 +04:00
parent 69e41447a6
commit 2c3b2dd68e
5 changed files with 201 additions and 121 deletions

View File

@ -32,12 +32,9 @@ import java.util.HashMap;
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 @@ public class AWTKeyStroke implements Serializable {
//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 @@ public class AWTKeyStroke implements Serializable {
}
/**
* 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 @@ public class AWTKeyStroke implements Serializable {
}
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 @@ public class AWTKeyStroke implements Serializable {
*/
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) {

View File

@ -26,6 +26,7 @@ package javax.swing;
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 @@ public class KeyStroke extends AWTKeyStroke {
*/
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 class KeyStroke extends AWTKeyStroke {
*/
public static KeyStroke getKeyStroke(char keyChar) {
synchronized (AWTKeyStroke.class) {
registerSubclass(KeyStroke.class);
return (KeyStroke)getAWTKeyStroke(keyChar);
}
}
@ -148,7 +158,6 @@ public class KeyStroke extends AWTKeyStroke {
*/
public static KeyStroke getKeyStroke(Character keyChar, int modifiers) {
synchronized (AWTKeyStroke.class) {
registerSubclass(KeyStroke.class);
return (KeyStroke)getAWTKeyStroke(keyChar, modifiers);
}
}
@ -199,7 +208,6 @@ public class KeyStroke extends AWTKeyStroke {
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 class KeyStroke extends AWTKeyStroke {
*/
public static KeyStroke getKeyStroke(int keyCode, int modifiers) {
synchronized (AWTKeyStroke.class) {
registerSubclass(KeyStroke.class);
return (KeyStroke)getAWTKeyStroke(keyCode, modifiers);
}
}
@ -266,7 +273,6 @@ public class KeyStroke extends AWTKeyStroke {
*/
public static KeyStroke getKeyStrokeForEvent(KeyEvent anEvent) {
synchronized (AWTKeyStroke.class) {
registerSubclass(KeyStroke.class);
return (KeyStroke)getAWTKeyStrokeForEvent(anEvent);
}
}
@ -307,7 +313,6 @@ public class KeyStroke extends AWTKeyStroke {
return null;
}
synchronized (AWTKeyStroke.class) {
registerSubclass(KeyStroke.class);
try {
return (KeyStroke)getAWTKeyStroke(s);
} catch (IllegalArgumentException e) {

View File

@ -97,6 +97,14 @@ public final class SwingAccessor {
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 final class SwingAccessor {
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;
}
}

View File

@ -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();
}
}
}
}

View File

@ -0,0 +1,2 @@
grant {
};