在我最终弄清楚为什么JWS 1.6.0_29无法启动1.4.2_12应用程序(请参见此问题)之后,我在启动1.4.2_12应用程序时遇到了另一个异常。使用JWS 1.6.0_29。
加载ResourceBundle时,我得到一个Missing ResourceExc0019。然而,message.properties文件确实存在于加载它的类的同一个包中。
当使用JWS 1.4或1.5启动应用程序时,不会引发异常
只有在启动应用程序时才会引发异常。使用JWS1.6。
完整的stackstrace是:
java.lang.ExceptionInInitializerError
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.sun.javaws.Launcher.executeApplication(Unknown Source)
at com.sun.javaws.Launcher.executeMainClass(Unknown Source)
at com.sun.javaws.Launcher.doLaunchApp(Unknown Source)
at com.sun.javaws.Launcher.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Caused by: java.util.MissingResourceException: Can't find bundle for base name com.test.hello.messages, locale fr_FR
at java.util.ResourceBundle.throwMissingResourceException(Unknown Source)
at java.util.ResourceBundle.getBundleImpl(Unknown Source)
at java.util.ResourceBundle.getBundle(Unknown Source)
at com.test.hello.Main.<clinit>(Main.java:10)
... 9 more
JNLP描述符是:
<?xml version="1.0" encoding="utf-8"?>
<jnlp spec="1.0+" codebase="http://localhost:80/meslegacy/apps" href="testJwsXXTo142.jnlp">
<information>
<title>JWS TEST 1.6 -> 1.4.2</title>
<vendor>Hello World Vendor</vendor>
<description>Hello World</description>
</information>
<security>
<all-permissions />
</security>
<resources>
<j2se version="1.4.2_12" href="http://java.sun.com/products/autodl/j2se" />
<jar href="jar/helloworld.jar" main="true" />
</resources>
<application-desc main-class="com.test.hello.Main" />
</jnlp>
com.test.hello.主要类是:
package com.test.hello;
import java.util.ResourceBundle;
import javax.swing.JFrame;
public class Main {
private static final ResourceBundle BUNDLE = ResourceBundle.getBundle(Main.class.getPackage().getName()+".messages");
public static void main(String[] args) {
JFrame frame = new JFrame("Hello world !");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800,600);
frame.setVisible(true);
}
}
手动加载资源的测试代码:
ClassLoader cl = Main.class.getClassLoader();
String resourcePath = baseName.replaceAll("\\.", "/");
System.out.println(resourcePath);
URL resourceUrl = cl.getResource(resourcePath+".properties");
System.out.println("Resource manually loaded :"+resourceUrl);
将产生:
com/test/hello/messages.properties
Resource manually loaded :jar:http://localhost:80/meslegacy/apps/jar/helloworld.jar!/com%2ftest%2fhello%2fmessages.properties
例子:
ClassLoader cl = Main.class.getClassLoader();
String resourcePath = baseName.replaceAll("\\.", "/") + ".properties";
URL resourceUrl = cl.getResource(resourcePath);
// here, resourceUrl is not null. Then build bundle by hand
ResourceBundle prb = new PropertyResourceBundle(resourceUrl.openStream());
它产生:
java.io.FileNotFoundException: JAR entry com%2ftest%2fhello%2fmessages.properties not found in C:\Documents and Settings\firstname.lastname\Application Data\Sun\Java\Deployment\cache\6.0\18\3bfe5d92-3dfda9ef
at com.sun.jnlp.JNLPCachedJarURLConnection.connect(Unknown Source)
at com.sun.jnlp.JNLPCachedJarURLConnection.getInputStream(Unknown Source)
at java.net.URL.openStream(Unknown Source)
at com.test.hello.Main.main(Main.java:77)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.sun.javaws.Launcher.executeApplication(Unknown Source)
at com.sun.javaws.Launcher.executeMainClass(Unknown Source)
at com.sun.javaws.Launcher.doLaunchApp(Unknown Source)
at com.sun.javaws.Launcher.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
似乎更像是缓存问题...
如果你们中的任何一个得到了暗示,我将不胜感激,
谢谢你的阅读。
下面是这个问题的解释和解决方法。
问题来自系统ClassCloader(JWS6系统ClassLoader)返回的URL。
对于JWS1.6,ClassLoader系统返回的URL包含如下所示的转义序列:
jar:http://localhost:80/meslegacy/apps/jar/helloworld.jar!/com%2ftest%2fhello%2fmessages.properties
在类路径中定位资源是可能的,但是当实际访问该资源的内容时,会引发FileNotFoundException:这就是ResourceBundle中FileNotFoundException的原因。
请注意,当URL中没有转义序列出现时,例如当资源位于CLASP路径的根时,访问资源内容没有问题。只有在URL路径部分中有%xx个内容时,问题才会出现。
一旦问题得到解决(我花了好几天的时间才弄清楚!),是时候为此找一个工作场所了。虽然我有可能在特定的本地化代码部分修复我的问题,但很快就发现,通过编写特定的类加载器来“替换”JNLPClassLoader,可以在全局范围内修复这个问题。我不会真正地“替换”,因为我觉得这是不可能的,但我宁愿做以下事情:
这将提供以下类加载器
public class JwsUrlFixerClassLoader extends URLClassLoader {
private final static Logger LOG = Logger.getLogger(JwsUrlFixerClassLoader.class);
private static String SIMPLE_CLASS_NAME = null;
private static boolean LOG_ENABLED = "true".equals(System.getProperty("classloader.debug"));
static {
SIMPLE_CLASS_NAME = JwsUrlFixerClassLoader.class.getName();
int idx = SIMPLE_CLASS_NAME.lastIndexOf('.');
if (idx >= 0 && idx < SIMPLE_CLASS_NAME.length()-1) {
SIMPLE_CLASS_NAME = SIMPLE_CLASS_NAME.substring(idx + 1);
}
}
public JwsUrlFixerClassLoader(URL[] urls, ClassLoader parent) {
super(urls, parent);
}
public URL getResource(String name) {
if (LOG.isDebugEnabled()) {
LOG.debug("getResource(): getResource(" + name + ")");
}
if (LOG_ENABLED) {
login("getResource(" + name + ")");
}
URL out = super.getResource(name);
if (out != null) {
out = URLFixerTool.fixUrl(out);
}
if (LOG_ENABLED) {
logout("getResource returning " + out);
}
return out;
}
public URL findResource(String name) {
if (LOG_ENABLED) {
login("findResource(" + name + ")");
}
URL out = super.findResource(name);
if (out != null) {
out = URLFixerTool.fixUrl(out);
}
if (LOG_ENABLED) {
logout("findResource returning " + out);
}
return out;
}
public InputStream getResourceAsStream(String name) {
if (LOG_ENABLED) {
login("getResourceAsStream(" + name + ")");
}
InputStream out = super.getResourceAsStream(name);
if (LOG_ENABLED) {
logout("getResourceAsStream returning " + out);
}
return out;
}
protected synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException {
if (LOG_ENABLED) {
login("loadClass(" + name + ")");
}
// First, check if the class has already been loaded
Class c = findLoadedClass(name);
if (c == null) {
try {
c = findClass(name);
} catch (ClassNotFoundException cnfe) {
if (getParent() == null) {
// c = findBootstrapClass0(name);
Method m = null;
try {
m = URLClassLoader.class.getMethod("findBootstrapClass0", new Class[] {});
m.setAccessible(true);
c = (Class) m.invoke(this, new Object[] { name });
} catch (Exception e) {
throw new ClassNotFoundException();
}
} else {
c = getParent().loadClass(name);
}
}
}
if (resolve) {
resolveClass(c);
}
if (LOG_ENABLED) {
logout("loadClass returning " + c);
}
return c;
}
private static void login(String message) {
System.out.println("---> [" + Thread.currentThread().getName() + "] " + SIMPLE_CLASS_NAME + ": " + message);
}
private static void logout(String message) {
System.out.println("<--- [" + Thread.currentThread().getName() + "] " + SIMPLE_CLASS_NAME + ": " + message);
}
}
现在,在我设置为JNLP描述符中的主类的AppBoostrap类中,我执行以下操作:
System.setSecurityManager(null);
ClassLoader parentCL = AppBootstrap.class.getClassLoader();
URL[] classpath = new URL[] {};
if (parentCL instanceof URLClassLoader) {
URLClassLoader ucl = (URLClassLoader) parentCL;
classpath = ucl.getURLs();
}
final JwsUrlFixerClassLoader vlrCL = new JwsUrlFixerClassLoader(classpath, parentCL);
Thread.currentThread().setContextClassLoader(vlrCL);
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
Thread.currentThread().setContextClassLoader(vlrCL);
}
});
} catch (Exception e) {
LOG.error("main(): Failed to set context classloader !", e);
}
在前面的摘录中,我得到了加载AppBootstrap类的类加载器,并将其用作JwsUrlFixerClassLoader的父类加载器。
我必须修复URLClassLodaer的默认父委托策略问题。loadClass()并将其替换为“先尝试我的类路径,然后尝试父类”。
在这之后,一切都正常了,还有一些我们至今无法解释的错误已经消失了。
真是神奇!在经历了很多痛苦之后。。。
希望有一天这能帮助别人。。。
我有最新的STS4。我使用安装的java-1.8 JDK未嵌入作为执行环境。我的项目运行良好,没有任何问题。 然而,当我启动STS应用程序时,我会弹出一个窗口,上面写着“Missing tools.jar” 我已经尝试过: 将指向不同的JDK 在文件中添加了args。 但我无法摆脱这个弹出窗口。
我有一份Java申请。 应用程序有一个决定应用程序是否在启动时启动的设置。 目前,我通过在StartUp items文件夹中放置/删除快捷方式实现了这一点。 然而,我想知道是否有更好的方法来处理这种行为。 编辑 是的,是视窗。抱歉之前没有清除。 应用程序有一个UI,用户可以在其中触发操作,并且应用程序在运行时定期在后台运行一些任务。 @Peter,如何使用应用程序中的代码更改注册表?这种方法是否与
我有一个导入到eclipse 3.4中的maven webapp项目,带有logback(1.0.9)日志记录。有: 主/资源/回溯.xml src/test/resources/logback-test.xml 当我在Tomcat中启动webapp时,由于Logback找到配置文件的顺序,logback-test.xml总是被加载。相反,我希望为应用程序启动加载logback.xml,并将log
问题内容: 我有一个Java应用程序。 该应用程序具有一个设置,该设置决定该应用程序是否在启动时启动。 目前,我可以通过在“启动项目”文件夹中放置/删除快捷方式来实现此目的。 但是,我想知道是否有更好的方法来处理此行为。 编辑 是的,它是Windows。抱歉,之前没有清除该内容。 该应用程序具有一个用户可以在其中触发动作的UI,并且该应用程序在运行时会定期在后台运行一些任务。 @Peter,如何在
得到 错误[SpringApplication]应用程序启动失败org.springframework.beans.factory.BeanCreationException:创建名称为myEntityManagerFactory的bean错误定义在类路径资源[com/员工/服务/配置/DBConfiguration.class]:调用init方法失败;嵌套异常是java.lang.NullPoi
我最近开始在我所有的项目中遇到这个问题。当我的索引页加载其中包含对jQuery源文件的引用时,我的控制台记录这个错误:。 这完全不影响我的应用程序,但是每当我打开控制台时,看到它真的很烦人。有人知道这是从哪里来的吗? 编辑:注意,我没有显式引用.map文件,我只是指向