在从JRE 1.7.0_21升级到1.7.0_25-b15后,我的应用程序开始在SwingUtilities.invoke稍后(...)从JavaWebStart运行。令人惊讶的是,当它作为独立应用程序(在JWS之外)执行时,它工作得很好。
这是堆栈的顶部:
Exception in thread "AWT-EventQueue-2" java.lang.NullPointerException
at sun.awt.SunToolkit.getSystemEventQueueImplPP(SunToolkit.java:1011)
at sun.awt.SunToolkit.getSystemEventQueueImplPP(SunToolkit.java:1007)
at sun.awt.SunToolkit.getSystemEventQueueImpl(SunToolkit.java:1002)
at java.awt.Toolkit.getEventQueue(Toolkit.java:1730)
at java.awt.EventQueue.invokeLater(EventQueue.java:1217)
at javax.swing.SwingUtilities.invokeLater(SwingUtilities.java:1290)
at AppletView$8.setBaseUnits(AppletView.java:536)
(...)
为了让您全面了解:方法setBaseUnits(…)作为远程服务器从RMI的回调调用。完整的堆栈跟踪相当长。
在RMI或JWS中,安全模型中是否存在可能会破坏东西的更改?如果是这样的话,我预计会出现一些安全异常,但可能是JRE中未正确检测到的,并导致NPE。
任何建议都将不胜感激。
----更新1:
0_25更新可能涉及一些安全更改和AppContext对象:https://forums.oracle.com/message/11080621https://forums.oracle.com/thread/2552799。我尝试建议修复:https://forums.oracle.com/message/11082162#11082162但没有任何成功。
我可以在我的应用程序中看到3个AWT EventQueue线程,编号从0到2。若程序是由JWS启动的,那个么JRE似乎会为不同的应用程序上下文创建额外的事件队列。JWS中有3个AppContext和3个EVT,如果程序是从IDE执行的,则只有一个context和EVT。
----更新2:
下面是古鲁曼建议的解决方法(非常感谢)。不幸的是,所有对SwingUtilities的调用。调用器(…)
,程序开始依赖Sun JRE内部API。
我仍然在寻找更一般的方法,而不是专门针对Sun JRE。我认为这是一个JRE错误。也许它可以以某种方式修补:AppContext在RMI线程中不应该为空。
----更新3:
我制作了一个简单的测试用例来说明这个问题。它由4个文件组成。要运行这个测试用例,需要对目标jar(TestCase.jar)进行签名。首先,在启动时指定正确的代码库。jnlp,然后通过JavaWebStart运行服务器(例如使用JavaWSLaunch.jnlp)。屏幕上应出现以下画面:
然后可以执行RMI客户端。成功执行后,框架应包括:
但是如果您尝试使用JWS执行服务器,您将在客户端程序中获得以下异常(异常从RMI服务器传播到RMI客户端):
Exception in thread "main" java.lang.NullPointerException
at sun.awt.SunToolkit.getSystemEventQueueImplPP(SunToolkit.java:1011)
at sun.awt.SunToolkit.getSystemEventQueueImplPP(SunToolkit.java:1007)
at sun.awt.SunToolkit.getSystemEventQueueImpl(SunToolkit.java:1002)
at java.awt.Toolkit.getEventQueue(Toolkit.java:1730)
at java.awt.EventQueue.invokeLater(EventQueue.java:1217)
at javax.swing.SwingUtilities.invokeLater(SwingUtilities.java:1290)
at testcase.RmiServiceImpl.callBack(RmiServiceImpl.java:70)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:322)
at sun.rmi.transport.Transport$1.run(Transport.java:177)
at sun.rmi.transport.Transport$1.run(Transport.java:174)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.Transport.serviceCall(Transport.java:173)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:553)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:808)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:667)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:724)
at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:273)
at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:251)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:160)
at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:194)
at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:148)
at com.sun.proxy.$Proxy0.callBack(Unknown Source)
at testcase.RmiClient.main(RmiClient.java:22)
这里是测试用例文件:
1) JNLP文件定义启动。jnlp:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<jnlp codebase="file:/home/user/NetBeansProjects/TestCase/dist/" href="launch.jnlp" spec="1.0+">
<information>
<title>TestCase</title>
<vendor>digital_infinity</vendor>
<homepage href=""/>
<description>TestCase</description>
<description kind="short">TestCase</description>
</information>
<security>
<all-permissions/>
</security>
<update check="always"/>
<resources>
<j2se version="1.7+"/>
<jar href="TestCase.jar" main="true"/>
</resources>
<application-desc main-class="testcase.RmiServiceImpl">
</application-desc>
</jnlp>
2)RMI接口定义(RmiService.java):
package testcase;
public interface RmiService extends java.rmi.Remote {
void callBack() throws java.rmi.RemoteException;
}
3) RMI服务代码和服务主类:
package testcase;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
/**
*/
public class RmiServiceImpl extends java.rmi.server.UnicastRemoteObject
implements RmiService {
final static int PORT = 1099;
static JFrame frame;
static JTextField textField;
public RmiServiceImpl() throws RemoteException {
super(PORT);
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) throws Exception {
Registry reg;
RmiServiceImpl service = new RmiServiceImpl();
try {
reg = LocateRegistry.getRegistry(PORT);
reg.rebind("test", service);
} catch (RemoteException ex) {
reg = LocateRegistry.createRegistry(PORT);
reg.rebind("test", service);
}
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
frame = new JFrame("Test App");
textField = new JTextField("Before call to callBack");
frame.getContentPane().add(textField);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
/** RMI callback */
public void callBack() {
Runnable rn = new Runnable() {
public void run() {
textField.setText("CallBack succesfully called.");
frame.pack();
}
};
SwingUtilities.invokeLater(rn);
}
}
4) 简单客户端代码:
package testcase;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class RmiClient {
public static void main(String[] args) throws Exception {
//now we trying to communicate with object through RMI
Registry reg = LocateRegistry.getRegistry(RmiServiceImpl.PORT);
//after got the registry, lookup the object and finally do call
RmiService serv = (RmiService) reg.lookup("test");
serv.callBack();
}
}
----更新4:
我提交的JRE Bug:http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=8019272
其他相关错误:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=8019274
这里是JDK-8019274的一个变通方法,打包在一个实用程序类中。对我们来说,invokeAndWait()仍然是一个问题。此示例具有invokeLater()的现有修复程序和invokeAndWait()的新修复程序。
笔记:
(免责声明:这是从我们的产品。此解决方案的某些方面可能不适用于您。(
public class JreFix {
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().
*/
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 {
SwingUtilities.invokeLater(runnable);
}
}
public static void invokeNowOrWait(Runnable runnable) {
if (hasAppContextBug()) {
fixThreadAppContext(null);
}
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(awtEventDispatchContext, runnable);
}
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, 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>" +
"Our application cannot run using <b>Web Start</b> 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;
}
}
该问题出现在Webstart环境中。在Java7u25的Webstart版本之前,AppContext是在系统线程组上设置的。但它是在主线程组上设置的。
如果您有一个基于线程组的线程,而它的父线程组或父线程组不是主线程组,那么它就没有sun。awt。AppContext。
您应该基于安全管理器的线程组(如果存在)创建线程。
Runnable task = ....
ThreadGroup threadGroup = System.getSecurityManager() != null
? System.getSecurityManager().getThreadGroup()
: Thread.currentThread().getThreadGroup();
Thread t = new Thread(threadGroup, task, "my thread", 0);
我找到了一个更好的解决方案。
在调用SwingUtilities或任何与Swing相关的组件方法之前,我刚刚添加了以下代码。它为RMI线程创建一个新的AppContext(运行下面的代码时,RMI线程必须是当前线程)。
if(AppContext.getAppContext() == null){
SunToolkit.createNewAppContext();
}
由于我的应用程序的需要,我能够将它添加到一个单一的方法,是使用SwingU实用程序,但您可能需要添加到您的RMI Callable Object的每个方法。
代码只需要运行一次,因此请检查应用程序的行为。
问题内容: 我刚刚遇到了这个“错误”,但是我不确定这是否是故意的:代码: 在第一个示例中,它是在swing线程上执行的,但在第二个示例中,它不是,尽管我认为应该这样做。 这是错误还是故意的? 问题答案: 在我看来,这似乎是您的误解 第一行就像在说:“好吧,秋千,我想要你做的是”。所以Swing执行它 第二行就像是说:“确定,Swing,我要您执行的是方法返回的对象的方法”。一个是方法, 我现在执行
最新开放的jdk是否保留对Javawebstart的支持? 当在eclipse中使用openjdk构建Java程序时,它能在安装了常规oracle jre的系统上运行吗? 我很好奇,因为如果openjdk仍然有JWS,我想尝试并开始使用它(可能是更新版本12)。但是,如果客户机安装了oracle jre 12,他们是否能够通过我的openjre应用程序构建来运行webstart?我这样问是因为我们
nodejs ASPnet5 unity office
我要迁移一个JavaApplet通过JNLP启动,作为一个Java的Web Start应用程序,并遇到一些麻烦/误解... 我得到的资源之一是这样的:6迁移JavaAppletJavaWeb Start和JNLP: 让我们开始吧,但是: 目前,该应用程序是一个小程序(),过去是通过将小程序标记嵌入到HTML中来启动的,小程序标记指的是JNLP。 现在,由于所有浏览器都放弃了对小程序的支持,我应该将
当我在我的三星Galaxy双机上运行这个应用程序时(没有在其他设备上测试),它会给我错误/异常
我创建了一个程序来处理数据库,我在IntelliJ IDEA中编译时遇到了以下错误。有人知道为什么会发生这种情况吗?我该如何解决它?