8336654: [lworld] Tests depending on sun.awt.AppContext can fail when run with migrated classes

Reviewed-by: serb, azvegint
This commit is contained in:
Phil Race 2026-01-08 19:47:01 +00:00
parent 1342db0bde
commit 982aa3f8ea
4 changed files with 33 additions and 143 deletions

View File

@ -35,8 +35,6 @@ import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.plaf.UIResource;
import sun.awt.AppContext;
import sun.lwawt.macosx.CPlatformWindow;
import sun.swing.SwingUtilities2;
@ -150,13 +148,34 @@ final class AquaUtils {
protected abstract T create();
}
abstract static class RecyclableSingleton<T> {
final T get() {
return AppContext.getSoftReferenceValue(this, () -> getInstance());
}
abstract static class LazySingleton<T> {
T instance;
void reset() {
AppContext.getAppContext().remove(this);
final T get() {
if (instance == null) {
instance = getInstance();
}
return instance;
}
abstract T getInstance();
}
abstract static class RecyclableSingleton<T> {
SoftReference<T> ref;
final T get() {
T instance;
if (ref != null) {
instance = ref.get();
if (instance != null) {
return instance;
}
}
instance = getInstance();
ref = new SoftReference<>(instance);
return instance;
}
abstract T getInstance();
@ -197,11 +216,11 @@ final class AquaUtils {
protected abstract V getInstance(K key);
}
private static final RecyclableSingleton<Boolean> enableAnimations = new RecyclableSingleton<Boolean>() {
private static final LazySingleton<Boolean> enableAnimations = new LazySingleton<Boolean>() {
@Override
protected Boolean getInstance() {
final String sizeProperty = System.getProperty(ANIMATIONS_PROPERTY);
return !"false".equals(sizeProperty); // should be true by default
final String animationsProperty = System.getProperty(ANIMATIONS_PROPERTY);
return !"false".equals(animationsProperty); // should be true by default
}
};
private static boolean animationsEnabled() {

View File

@ -47,7 +47,6 @@ import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;
/**
* The AppContext is a table referenced by ThreadGroup which stores
@ -735,24 +734,6 @@ public final class AppContext {
}
return changeSupport.getPropertyChangeListeners(propertyName);
}
public static <T> T getSoftReferenceValue(Object key,
Supplier<T> supplier) {
final AppContext appContext = AppContext.getAppContext();
@SuppressWarnings("unchecked")
SoftReference<T> ref = (SoftReference<T>) appContext.get(key);
if (ref != null) {
final T object = ref.get();
if (object != null) {
return object;
}
}
final T object = supplier.get();
ref = new SoftReference<>(object);
appContext.put(key, ref);
return object;
}
}
final class MostRecentKeyValue {

View File

@ -29,7 +29,6 @@ import java.awt.*;
import java.lang.ref.*;
import java.util.*;
import java.util.concurrent.locks.*;
import sun.awt.AppContext;
/**
* ImageCache - A fixed pixel count sized cache of Images keyed by arbitrary
@ -37,8 +36,6 @@ import sun.awt.AppContext;
* dropped by the GC if heap memory gets tight. When our size hits max pixel
* count least recently requested images are removed first.
*
* The ImageCache must be used from the thread with an AppContext only.
*
*/
public final class ImageCache {
@ -56,9 +53,10 @@ public final class ImageCache {
// Reference queue for tracking lost softreferences to images in the cache
private final ReferenceQueue<Image> referenceQueue = new ReferenceQueue<>();
private static final ImageCache instance = new ImageCache();
public static ImageCache getInstance() {
return AppContext.getSoftReferenceValue(ImageCache.class,
() -> new ImageCache());
return instance;
}
ImageCache(final int maxPixelCount) {

View File

@ -1,108 +0,0 @@
/*
* Copyright (c) 2009, 2018, 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.
*/
/*
* @test
* @bug 6657138
* @summary Verifies that buttons and labels don't share their ui's across appContexts
* @author Alexander Potochkin
* @modules java.desktop/sun.awt
*/
import sun.awt.SunToolkit;
import javax.swing.*;
import javax.swing.plaf.ButtonUI;
import javax.swing.plaf.ComponentUI;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class bug6657138 implements Runnable {
private static Map<JComponent, Map<String, ComponentUI>> componentMap =
Collections.synchronizedMap(
new HashMap<JComponent, Map<String, ComponentUI>>());
public void run() {
SunToolkit.createNewAppContext();
try {
testUIMap();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static void testUIMap() throws Exception {
UIManager.LookAndFeelInfo[] lafs = UIManager.getInstalledLookAndFeels();
Set<JComponent> components = componentMap.keySet();
for (JComponent c : components) {
Map<String, ComponentUI> uiMap = componentMap.get(c);
for (UIManager.LookAndFeelInfo laf : lafs) {
if ("Nimbus".equals(laf.getName())) {
// for some unclear reasons
// Nimbus ui delegate for a button is null
// when this method is called from the new AppContext
continue;
}
String className = laf.getClassName();
try {
UIManager.setLookAndFeel(className);
} catch (final UnsupportedLookAndFeelException ignored) {
continue;
}
ComponentUI ui = UIManager.getUI(c);
if (ui == null) {
throw new RuntimeException("UI is null for " + c);
}
if (ui == uiMap.get(laf.getName())) {
throw new RuntimeException(
"Two AppContexts share the same UI delegate! \n" +
c + "\n" + ui);
}
uiMap.put(laf.getName(), ui);
}
}
}
public static void main(String[] args) throws Exception {
componentMap.put(new JButton("JButton"),
new HashMap<String, ComponentUI>());
componentMap.put(new JToggleButton("JToggleButton"),
new HashMap<String, ComponentUI>());
componentMap.put(new JRadioButton("JRadioButton"),
new HashMap<String, ComponentUI>());
componentMap.put(new JCheckBox("JCheckBox"),
new HashMap<String, ComponentUI>());
componentMap.put(new JCheckBox("JLabel"),
new HashMap<String, ComponentUI>());
testUIMap();
ThreadGroup group = new ThreadGroup("6657138");
Thread thread = new Thread(group, new bug6657138());
thread.start();
thread.join();
}
}