fix for JDK-8019274 Java 7u25, 7u40, 6u51 RMI bug with SwingUtilities.invokeLater() and SwingUtilities.invokeAndWait()
uinerd
uinerd at gmail.com
Wed Sep 25 12:48:47 PDT 2013
Here is the workaround, packaged in a utility class. (You'll need to
include the jnlp.jar in your project.)
Replace all your calls to invokeLater() and invokeAndWait() with
JreUtils.invokeNowOrLater() and JreUtils.invokeNowOrWait().
It's not a perfect solution, but if your web start app is offline because
of JDK-8019274, this should get it running again.
uinerd
Morrisville, NC
package com.uinerd;
import java.awt.Component;
import java.lang.reflect.Field;
import java.util.Map;
import javax.jnlp.BasicService;
import javax.jnlp.IntegrationService;
import javax.jnlp.ServiceManager;
import javax.jnlp.UnavailableServiceException;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;
import sun.awt.AppContext;
/**
* Encapsulates the Java 7u25/7u40/6u51 hack
*/
public class JreUtils {
private static String badVersionInfo = null;
private static AppContext awtEventDispatchContext = null;
private static AppContext mainThreadContext = null;
private static Boolean isWebStart = null;
private static BasicService basicService = null;
private static IntegrationService integrationService = null;
/**
* Call this early in main(). Do not call this using an invoke* method.
*/
public static void init() {
if (isWebstart() && isApplicableJvmType()) {
String javaVersion = System.getProperty("java.version");
if ("1.7.0_25".equals(javaVersion)) {
badVersionInfo = "7u25";
}
else if ("1.7.0_40".equals(javaVersion)) {
badVersionInfo = "7u40";
}
else if (javaVersion != null &&
"1.6.0_51".equals(javaVersion.substring(0,8))) {
badVersionInfo = "6u51";
}
else if
("javaws-10.25.2.16".equals(System.getProperty("javawebstart.version"))) {
badVersionInfo = "Web Start 10.25.2.16";
}
}
if (badVersionInfo != null) {
mainThreadContext = AppContext.getAppContext();
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
awtEventDispatchContext = AppContext.getAppContext();
}
});
}
catch (Exception e) {
displayErrorAndExit(null);
}
if (mainThreadContext == null || awtEventDispatchContext == null) {
displayErrorAndExit(null);
}
}
}
public static void invokeNowOrLater(Runnable runnable) {
if (hasAppContextBug()) {
invokeLaterOnAwtEventDispatchThreadContext(runnable);
}
else {
if (SwingUtilities.isEventDispatchThread()) {
runnable.run();
}
else {
SwingUtilities.invokeLater(runnable);
}
}
}
public static void invokeNowOrWait(Runnable runnable) {
if (hasAppContextBug()) {
fixThreadAppContext(null);
}
if (SwingUtilities.isEventDispatchThread()) {
runnable.run();
}
else {
try {
SwingUtilities.invokeAndWait(runnable);
}
catch (Exception e) {
// handle it
}
}
}
public static boolean hasAppContextBug() {
return isJreWithAppContextBug() && AppContext.getAppContext() == null;
}
public static void invokeLaterOnAwtEventDispatchThreadContext(Runnable
runnable) {
sun.awt.SunToolkit.invokeLaterOnAppContext(JreUtils.awtEventDispatchContext,
runnable);
}
// this is the important part
public static void fixThreadAppContext(Component parent) {
try {
final Field field =
AppContext.class.getDeclaredField("threadGroup2appContext");
field.setAccessible(true);
Map<ThreadGroup, AppContext> threadGroup2appContext =
(Map<ThreadGroup, AppContext>)field.get(null);
final ThreadGroup currentThreadGroup =
Thread.currentThread().getThreadGroup();
threadGroup2appContext.put(currentThreadGroup,
JreUtils.mainThreadContext);
}
catch (Exception e) {
displayErrorAndExit(parent);
}
if (AppContext.getAppContext() == null) {
displayErrorAndExit(parent);
}
}
private static boolean isJreWithAppContextBug() {
return badVersionInfo != null;
}
private static void displayErrorAndExit(Component parent) {
JLabel msgLabel = new JLabel("<html>" +
"Application cannot run using Web Start with this version of Java.<p><p>" +
"Java " + badVersionInfo + " contains a bug acknowledged by Oracle
(JDK-8019274).")
JOptionPane.showMessageDialog(parent, msgLabel, "Java Version Error",
JOptionPane.ERROR_MESSAGE);
System.exit(1);
}
private static boolean isApplicableJvmType() {
String vendor = System.getProperty("java.vendor");
String vmName = System.getProperty("java.vm.name");
if (vendor != null && vmName != null) {
return vmName.contains("Java HotSpot") &&
(vendor.equals("Oracle Corporation") ||
vendor.equals("Sun Microsystems Inc."));
}
return false;
}
private static boolean isWebstart() {
if (isWebStart == null) {
try {
basicService = (BasicService)
ServiceManager.lookup("javax.jnlp.BasicService");
isWebStart = true;
}
catch (UnavailableServiceException e) {
isWebStart = false;
}
try {
integrationService = (IntegrationService)
ServiceManager.lookup("javax.jnlp.IntegrationService");
}
catch (UnavailableServiceException e) {
}
}
return isWebStart;
}
}
More information about the jdk7u-dev
mailing list