简体   繁体   English

java.util.MissingResourceException-新File()不能进入jar-如何为外部库提供此File的路径?

[英]java.util.MissingResourceException - new File() does not reach into jar - how to provide external library with a path for this File?

The question started as - maven does not reach into jar for a folder bundle correctly, when running tests. 问题开始于-在运行测试时,maven无法正确进入文件夹捆绑的jar。 It does work currectly when running some main() though. 虽然运行某些main()时它确实可以正常工作。

The stack trace for running test (while building) looked like this: 用于运行测试(构建时)的堆栈跟踪如下所示:

Caused by: java.util.MissingResourceException: Can't find Not found profile: file:\C:\Users\Simon\.m2\repository\ario\TextProcessing\1.0.4-SNAPSHOT\TextProcessing-1.0.4-SNAPSHOT.jar!\lang bundle
at java.util.logging.Logger.setupResourceInfo(Logger.java:1942)
at java.util.logging.Logger.<init>(Logger.java:380)
at java.util.logging.LogManager.demandLogger(LogManager.java:554)
at java.util.logging.Logger.demandLogger(Logger.java:455)
at java.util.logging.Logger.getLogger(Logger.java:553)
at cz.techniserv.ario.tagger.TagDetect.setLangPath(TagDetect.java:126)
at cz.techniserv.ario.tagger.TagDetect.<init>(TagDetect.java:58)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:408)
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:147)
... 86 more

I triple checked - the lang folder is within the jar. 我三重检查-lang文件夹在jar中。

When running a main() within the module however, it does not try to reach into jar withing m2 repository, but will take the lang folder from within the opened dependency project. 但是,在模块中运行main()时,它不会尝试使用m2存储库进入jar,而是从打开的依赖项项目中获取lang文件夹。 So it does not try to reach into a jar, just takes the data from project folder. 因此,它不会尝试进入jar中,而只是从项目文件夹中获取数据。 This runs correctly. 这可以正常运行。

Apparently, the File() constructor is unable to reach for the resource in the jar. 显然,File()构造函数无法访问jar中的资源。

The code, that tries to reach into the jar is within a constructor. 试图进入jar的代码在构造函数中。 It looks like this: 看起来像这样:

this.path = this.getClass().getResource("/" + aLanguageDirectoryName).getPath();

and than there is a File constructor which takes this path. 然后有一个File构造函数采用此路径。

In case of running the app it resolves to the project path. 如果运行该应用程序,它将解析为项目路径。 When it runs tests it will resolve to the jar within the m2 repository and tries to reach within the path that is in the exception: 运行测试时,它将解析为m2存储库中的jar,并尝试到达异常路径中:

file:\C:\Users\Simon\.m2\repository\ario\TextProcessing\1.0.4-SNAPSHOT\TextProcessing-1.0.4-SNAPSHOT.jar!\lang

What would you do? 你会怎么做? Would you copy the resource "lang" folder on some temporary path and provide the library with this new non-within-jar temporary path, so that it can open with the File() constructor? 您是否会在某个临时路径上复制资源“ lang”文件夹,并为该库提供此新的非jar临时路径,以便可以使用File()构造函数打开它? Or do you see another better way? 还是您看到另一种更好的方法?

Ok, so what we did is that the data are ad hoc extracted to classpath and accessed. 好的,所以我们要做的是将数据临时提取到类路径并访问。

The problem with this solution is that if you delete the files after usage, than you will always extract and delete data with each run - when this happens with every spring initialization of running tests this can happen extreme amount of times and take a lot of time. 该解决方案的问题在于,如果您在使用后删除文件,那么每次运行都将始终提取和删除数据 -当运行测试的每个Spring初始化都发生这种情况时,这可能会花费大量时间并花费大量时间。 Leaving the data there however means that if the path is not absolute and out of the project trunk folder, SCM will pick it up unless you ignore it and commit the data which is not satisfying. 但是将数据保留在那里意味着如果路径不是绝对路径并且不在项目主干文件夹之外,除非您忽略它并提交不令人满意的数据,否则SCM会选择它 Also they get packed into the jar upon build since they are on classpath which is another drawback. 由于它们在类路径上,因此它们在构建时被打包到jar中,这是另一个缺点。 Yes, you can ignore with SCM and configure maven to exclude the folder, however some developers will forget (one already did) to ignore with SCM and it was commited. 是的,您可以忽略SCM并将maven配置为排除该文件夹,但是有些开发人员会忘记(已经做过)忽略SCM并提交。

We consider extracting to an absolute path which would not be on classpath a bad practice - firstly because you have no control on what system the projects run on so you cannot guess very well the absolute path - also it does not look pretty to throw data around your computer for bad design. 我们认为将提取到绝对路径不会在类路径上是一个坏习惯 -首先,因为您无法控制项目在哪个系统上运行,因此您无法很好地猜出绝对路径-而且将数据丢到外面看起来也不是很漂亮您的计算机设计错误。

So I guess the best thing would be to push everyone to place the data on some place on their discs and set an environment variable which would be the same for everyone. 因此,我认为最好的办法是推动每个人将数据放在其光盘上的某个位置,并设置一个对每个人都相同的环境变量 This makes the project less portable, requires more configuration, but removes formerly mentioned problems. 这使项目的可移植性降低,需要更多的配置,但消除了前面提到的问题。

I did not come up with anything better. 我没有想出更好的办法。

In case anyone would want to do the same thing, here is our code: 万一有人想做同样的事情,这是我们的代码:

    CodeSource src = this.getClass().getProtectionDomain().getCodeSource();
    if (src == null) {
        return null;
    }
    URL jarURL = src.getLocation();
    try (JarFile jar = new JarFile(jarURL.getPath());) {
        Enumeration<JarEntry> enumEntries = jar.entries();
        while (enumEntries.hasMoreElements()) {
            JarEntry fileFromJar = (JarEntry) enumEntries.nextElement();
            File toBeCreatedFileLocally = new File(NAME_FOR_TEMPORARY_FOLDER_TO_HOLD_LANG_DATA_FROM_JAR + File.separator + fileFromJar.getName());
            if (fileFromJar.isDirectory()) {
                continue;
            }
            if (fileFromJar.getName().contains(aLanguageDirectoryName)) {
                toBeCreatedFileLocally.getParentFile().mkdirs();
                try (InputStream is = jar.getInputStream(fileFromJar); // get the input stream
                        FileOutputStream fos = new FileOutputStream(toBeCreatedFileLocally)) {
                    while (is.available() > 0) {  // write contents of 'is' to 'fos'
                        fos.write(is.read());
                    }
                }
            }
        }
    } catch (IOException ex) {
        Logger.getLogger(TagDetect.class.getName()).log(Level.SEVERE, null, ex);
    }

This code is actually a modification of a different answer here https://stackoverflow.com/a/1529707/1920149 (beware, that answer has a bug, check comments - they rejected my edit) 这段代码实际上是这里https://stackoverflow.com/a/1529707/1920149的另一个答案的修改(请注意,该答案有错误,请检查注释-他们拒绝了我的编辑)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 运行jar时出现java.util.MissingResourceException - java.util.MissingResourceException when running a jar 获取java.util.MissingResourceException的Tomcat \\ bin文件夹中的属性文件 - Property file in Tomcat\bin folder getting java.util.MissingResourceException 当访问属性文件时,Spring Boot java.util.MissingResourceException - Spring boot java.util.MissingResourceException while accessing properties file java.util.MissingResourceException - java.util.MissingResourceException java.util.MissingResourceException: - java.util.MissingResourceException: java.util.MissingResourceException-定位日志记录类时出错(MQTT库) - java.util.MissingResourceException - Error locating the logging class (MQTT Library) ControlsFX 8.0.6对话框java.util.MissingResourceException - ControlsFX 8.0.6 dialogs java.util.MissingResourceException 资源包中的java.util.MissingResourceException - java.util.MissingResourceException in Resource bundle Vaadin国际化问题:java.util.MissingResourceException - Vaadin internationalization issue: java.util.MissingResourceException 加载 Java.properties 文件,获取 java.util.MissingResourceException:找不到基本名称的捆绑包我做错了什么? - Loading a Java .properties file, getting java.util.MissingResourceException: Can't find bundle for base name what am I doing wrong?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM