我们有一个java web start应用程序正在使用java 8,但是在Java 9上运行它会崩溃。
应用程序加载一个新的JavaFx场景,其中包含一个webview,它显示一个包含菜单的网页,该菜单包含不同的按钮,每个按钮打开一个内容使用thinlet的新窗口。
出于安全考虑,我们正在加密jar。因此,当我们运行应用程序时,我们将使用我们自己的类加载器替换类加载器,该类加载器将首先解密jar的加密类。
单击任何按钮,我们使用自己的类加载器使用反射调用加密类,并使该类的默认类加载器成为我们自己的类,因此所有其余的类都可以在解密之后启动。 / p>
直到java 9才能正常工作。但是在java 9上运行应用程序时,我第一次单击任何按钮时应用程序正确启动但在此之后我每次单击按钮时都会出现这种情况。得到一个
java.lang.reflect.InvocationTargetException
由jdk类中的java.lang.NullPointerException引起。不同的按钮之间的跟踪是不同的,但有一个共同的部分,这是我运行一个简单的样本的例外:
java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at com.glt.cryptoclass.DecryptingClassLoader$PrivilegedLaunch.run(DecryptingClassLoader.java:56)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at com.glt.cryptoclass.DecryptingClassLoader.launch(DecryptingClassLoader.java:179)
at com.glt.replace.Browser$1.call(Browser.java:58)
at com.glt.replace.Browser$1.call(Browser.java:42)
at javafx.graphics/javafx.concurrent.Task$TaskCallable.call(Unknown Source)
at java.base/java.util.concurrent.FutureTask.run(Unknown Source)
at java.base/java.lang.Thread.run(Unknown Source)
Caused by: java.lang.NullPointerException
at java.desktop/java.awt.Window.addToWindowList(Unknown Source)
at java.desktop/java.awt.Window.init(Unknown Source)
at java.desktop/java.awt.Window.<init>(Unknown Source)
at java.desktop/java.awt.Frame.<init>(Unknown Source)
at com.thinlet.FrameLauncher.<init>(FrameLauncher.java:32)
at com.glt.replace.start.miau(start.java:32)
at com.glt.replace.start.main(start.java:22)
... 12 more
我已经研究了很长时间,我发现可能我必须打开并导出一些模块才能使其正常工作。我已经在jnlp打开并导出下一个模块:
<j2se version="1.6+" href="http://java.sun.com/products/autodl/j2se" java-vm-args="--add-opens=java.management/sun.management=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.security=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.desktop/java.awt=ALL-UNNAMED --add-exports java.management/sun.management=ALL-UNNAMED --add-exports java.base/java.lang=ALL-UNNAMED --add-exports java.base/java.util=ALL-UNNAMED --add-exports java.base/java.security=ALL-UNNAMED --add-exports java.base/java.lang.reflect=ALL-UNNAMED --add-exports java.base/java.util.concurrent=ALL-UNNAMED --add-exports=java.desktop/java.awt=ALL-UNNAMED --add-modules=java.xml.ws"/>
此外,我已经运行了jdep -jdkinternals命令,看看我是否使用了任何冲突库,但我没有得到任何东西。
此外,如果我在没有加密的情况下运行应用程序,或者在本地运行加密,它可以正常运行。任何人都能指出我的意思 我可能做错了吗?或者知道为什么在jnlp上运行时的行为与我在本地运行它时的行为不同?
我还添加了一些可能有用的代码: 主类(包含Web引擎):
public void start(Stage primaryStage) throws Exception {
this.stage = primaryStage;
SwingUtilities.invokeLater(this);
}
public void run() {
initAndShowGUI();
}
/**
* Invokes platform run later to start the application
* on the event dispatcher
*/
private void initAndShowGUI() {
Platform.runLater(new Runnable() {
public void run() {
initFX(stage);
}
});
}
/**
* initialise the stage get as a parameter
* @param stage stage to initialise
*/
private void initFX(Stage stage){
// browser = new Browser();
browser = new Browser();
scene = new Scene(browser,1050,700,Color.web("#666970"));
stage.setScene(scene);
stage.setTitle("TEST");
scene.getStylesheets().add("webviewsample/BrowserToolbar.css");
stage.show();
//edit action on close
stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
@Override
public void handle(WindowEvent event) {
// try {
// //WARNING uninstall all the javaws applications TODO fin the way to know the jnlp path
// Runtime.getRuntime().exec("javaws -uninstall");
// } catch (IOException ex) {
// ex.printStackTrace();
// }
System.out.println("INFO: Stage is closing...");
Platform.exit();
System.exit(0);
}
});
}
/**
* class that extends Region and implements the handler for
* the html content from the home applet web page
* @param args
*/
public static void main(String[] args){
String base = "";
System.out.println("telekey.TeleKeyJnlp.main(). DEBUG: Reading arguments.");
for(String arg : args){
System.out.println("telekey.TeleKeyJnlp.main(). DEBUG: argument: " + arg);
if(arg.contains(BASE_URL) || arg.contains(SHORT_BASE_URL)){
System.out.println("telekey.TeleKeyJnlp.main(). DEBUG: Argument found.");
String []parts = arg.split(ARGUMENT_SEPARATOR);
if(parts.length > 1){
System.out.println("telekey.TeleKeyJnlp.main(). DEBUG: Setting Base URL.");
base = parts[1];
}
}
}
if(base.isEmpty()){
System.out.println("telekey.TeleKeyJnlp.main(). DEBUG: Base URL empty, setting base URL to " + DEFAULT_TK);
base = DEFAULT_TK;
}
launch(args);
}
我们自己的WebEngine:
public void launch(final String className, final String[] args) {
try {
initWebView();
//start new thread to the new window
javafx.concurrent.Task configTask = new javafx.concurrent.Task<Void>() {
@Override
protected Void call() {
//ModConfig.main(args) // ModBrowser.main(args);
try {
if (dcl == null) {
KeyGetter key = new KeyGetter("https://www.telekey.nl/", "getReplaceKeyDetails.jsp");
//
key.fetchKeyDetails();
System.out.println(".actionPerformed(): DEBUG. key details: "
+ key.getAlgorithm() + "\n"
+ key.getCypherDesc() + "\n"
+ key.getRawKey());
dcl = new DecryptingClassLoader(key);
}
Class[] parTypes = {String[].class};
dcl.launch(className, "main", args, parTypes, true);
} catch (Exception ex) {
ex.printStackTrace();
} finally {
return null;
}
}
};
new Thread(configTask).start();
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void processNewLocation(String newLocation){
String []args = null;
if(newLocation != null && !newLocation.equals("https://www.google.nl/")){
launch("com.glt.replace.start", args);
}
}
public void initWebView() {
if (getChildren().contains(browser)) {
getChildren().remove(browser);
}
browser = null;
browser = new WebView();
webEngine = browser.getEngine();
//Set user agent to indicate we are on java fx webView
webEngine.setUserAgent(webEngine.getUserAgent() + " JavaFX-WebView");
webEngine.setJavaScriptEnabled(true);
webEngine.locationProperty().addListener((ObservableValue<? extends String> observable, String oldLocation, String newLocation) -> {
processNewLocation(newLocation);
});
webEngine.load("https://www.google.nl/"); // works but it does not have style
getChildren().add(browser);
}
我们运行的课程更改搜索谷歌上的内容(更改位置):
public static void main(String[] args) {
start s = new start();
s.miau();
}
private void miau() {
FrameLauncher f = new FrameLauncher("secundary", new Thinlet(), 300, 300);
System.out.println("com.glt.main.start.main(). DEBUG: Miau!!");
f.setVisible(true);
}
更新1 :
我发现安全管理员遇到了问题。如果我评论该行,我的简单程序就可以了。但是,我们必须替换类加载器才能拥有一些权限。有谁知道为什么我不能在javafx9应用程序中设置安全管理器的原因?或者,我可能做错了什么?该应用程序使用jarsigner进行签名。
更新2 : 我还向java发送了一个bug请求,这里是它的url: https://bugs.openjdk.java.net/browse/JDK-8186568