简体   繁体   English

classLoader.getResourceAsStream 在测试中返回一个空的 Stream

[英]classLoader.getResourceAsStream returns an empty Stream in Testing

I have a method where I need to read a resource file and pass it to another method as an InputStream.我有一个方法需要读取资源文件并将其作为 InputStream 传递给另一个方法。 The obvious approach显而易见的方法

InputStream is = classLoader.getResourceAsStream("filename.pem");

works fine when actually running the application, but in testing it returns an empty InputStream (filled with zeros).在实际运行应用程序时工作正常,但在测试中它返回一个空的 InputStream(用零填充)。 I don't think its a problem with the resource path or anything, because when I use a nonsense path like "filex" (filex does not exist), I get an actual null pointer exception and not an empty stream. Also in debugger the complete file path of the empty Stream points to the correct path, where the file actually is stored (default class root).我不认为这是资源路径或任何问题,因为当我使用像"filex"这样的无意义路径(filex 不存在)时,我得到一个实际的 null 指针异常而不是一个空的 stream。同样在调试器中空 Stream 的完整文件路径指向正确的路径,文件实际存储的位置(默认 class root)。

Furthermore, with the following workaround it works:此外,通过以下解决方法它可以工作:

            File file = new File(classLoader.getResource("filename.pem").getFile());
            String fileS= new String(Files.readAllBytes(file.toPath()), Charset.defaultCharset());
            InputStream is = classLoader.getResourceAsStream("filename.pem");
            InputStream is2 = new ByteArrayInputStream(fileS.getBytes(StandardCharsets.UTF_8));

In this example is2 has the actual content of the file in the InputStream, while is has an Stream filled with zeros.在此示例中, is2具有 InputStream 中文件的实际内容,而is具有填充了零的 Stream。 I can't quite explain that behaviour.我无法完全解释这种行为。 I double checked with 'getClass().getClassLoader().getClass()' if we use some modified ClassLoader in the Application, but it is the original one from sun.misc.Launcher$AppClassLoader .如果我们在应用程序中使用一些修改过的 ClassLoader,我会仔细检查“getClass().getClassLoader().getClass()”,但它是来自sun.misc.Launcher$AppClassLoader的原始类加载器。

So my questions are:所以我的问题是:

  • Why does the workaround work but not the classic approach?为什么变通方法有效但经典方法无效?
  • Why does it fail only in test class?为什么它只在测试 class 中失败?
  • Is there a way to make it work?有没有办法让它工作? The workaround is more lines of code and also need to catch IOException because of the Files.readAllBytes() call.解决方法是使用更多代码行,并且还需要捕获 IOException 因为调用了Files.readAllBytes()

The only idea I had left: the encoding or charset has something to do with it.我唯一的想法是:编码或字符集与它有关。 But to my knowledge there is no parameter in getResourceAsStream() like Charset or StandardCharsets .但据我所知, getResourceAsStream()中没有像CharsetStandardCharsets这样的参数。

If you open a resource file as a stream, you end up with a BufferedInputStream around a FileInputStream .如果您将资源文件打开为 stream,您最终会在FileInputStream周围得到一个BufferedInputStream

The call chain is as follows:调用链如下:

  • java.lang.ClassLoader#getResource returns an URL java.lang.ClassLoader#getResource返回一个URL
  • url.openStream() is called url.openStream()被调用
  • this first opens the Stream;这首先打开 Stream; sun.net.www.protocol.file.Handler#createFileURLConnection
  • then the Stream is connected: is = new BufferedInputStream(new FileInputStream(filename));然后连接 Stream: is = new BufferedInputStream(new FileInputStream(filename)); in sun.net.www.protocol.file.FileURLConnection#connectsun.net.www.protocol.file.FileURLConnection#connect
  • finally you get this is back as InputStream最后你is这个作为InputStream回来了

What you're seeing is the empty internal buffer of the BufferedInputStream , which will be used as soon as you start reading from the InputStream.您看到的是BufferedInputStream的空内部缓冲区,一旦您开始从 InputStream 读取数据,它就会被使用。 See is FileInputStream not buffered and why BufferedInputStream is faster?查看FileInputStream 是否未缓冲以及为什么 BufferedInputStream 更快?

If you for example read from the InputStream with all zero's, you will see it does actually contain data:例如,如果您从全零的 InputStream 中读取,您将看到它确实包含数据:

Scanner scanner = new Scanner(inputStream, StandardCharsets.UTF_8.name());
String firstLine = scanner.next();

From https://www.baeldung.com/convert-input-stream-to-string来自https://www.baeldung.com/convert-input-stream-to-string

Your workaround works, because after you've located the file from the resource URL you actually start reading it directly.您的解决方法有效,因为在您从资源 URL 中找到文件后,您实际上开始直接读取它。

So what might be failing in your test;那么您的测试可能会失败的原因是什么? are you not trying to read from the stream in your testcase?你不是想从你的测试用例中读取 stream 吗? How are you using/validating if this inputstream is correct in your test vs the real application?您如何使用/验证此输入流在您的测试中与实际应用程序中是否正确? There might be the problem.可能有问题。

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM