InputStream.getResourceAsStream()给出空指针exception
行persistenceProperties.load(is);
在以下方法中抛出nullpointerexception
。 我该如何解决这个错误?
public void setUpPersistence(){ final Properties persistenceProperties = new Properties(); InputStream is = null; try { is = getClass().getClassLoader().getResourceAsStream("src/test/samples/persistence.properties"); persistenceProperties.load(is); }catch (IOException ignored) {} finally { if (is != null) {try {is.close();} catch (IOException ignored) {}} } entityManagerFactory = Persistence.createEntityManagerFactory( "persistence.xml", persistenceProperties); }
我试图通过将包含该方法的类移动到应用程序结构中的各个其他位置,并通过以下方式更改错误之前的代码行来尝试此操作:
is = getClass().getClassLoader().getResourceAsStream("persistence.properties"); is = getClass().getClassLoader().getResourceAsStream("/persistence.properties"); is = getClass().getClassLoader().getResourceAsStream("/src/test/samples/persistence.properties"); is = getClass().getClassLoader().getResourceAsStream("other/paths/after/moving/persistence.properties");
但每次调用该方法时仍会抛出错误。
这是eclipse项目目录结构的打印屏幕。 包含该方法的类称为TestFunctions.java
,并显示persistence.properties
的位置:
**编辑:**
根据下面的反馈,我将方法更改为:
public void setUpPersistence(){ final Properties persistenceProperties = new Properties(); InputStream is = null; try { is = getClass().getClassLoader().getResourceAsStream("persistence.properties"); persistenceProperties.load(is); }catch (IOException i) {i.printStackTrace();} finally { if (is != null) {try {is.close();} catch (IOException ignored) {}} } entityManagerFactory = Persistence.createEntityManagerFactory( "persistence.xml", persistenceProperties); }
我还将mainTest.TestFunctions.java移动到src/test/java
。 这些都会导致以下新的堆栈跟踪:
Exception in thread "main" java.lang.NoClassDefFoundError: maintest/TestFunctions at maintest.Main.main(Main.java:7) Caused by: java.lang.ClassNotFoundException: maintest.TestFunctions at java.net.URLClassLoader$1.run(URLClassLoader.java:202) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:190) at java.lang.ClassLoader.loadClass(ClassLoader.java:306) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301) at java.lang.ClassLoader.loadClass(ClassLoader.java:247) ... 1 more
简短回答:将persistence.properties移动到src / main / resources,在src / main / java中同时使用Main.java和TestFunctions.java,并使用
getClass().getClassLoader().getResourceAsStream("persistence.properties");
加载属性文件。
很长的答案和解释:
正如其他人所暗示的那样 – 在Maven项目结构中,您(通常)有两个目录树: /src/main
和/src/test
。 一般意图是任何“真正的”代码,资源等应该放在/src/main
,而仅测试的项应该放在/src/test
。 编译和运行时, test
树中的项目通常可以访问main
树中的项目,因为它们用于测试main中的项目; 但是, main
树中的项目通常不能访问test
树中的项目,因为根据测试内容生成“生产”代码通常是个坏主意。 因此,由于Main.java依赖于TestFunctions.java,而TestFunctions.java依赖于persistence.properties,如果Main位于src/main
那么TestFunctions和persistence.properties也需要同样。
两件事情:
首先,尝试一下test/samples/...
或/test/samples/...
的路径
其次,更重要的是,永远不要写这个:
try { // some stuff } catch (IOException ignored) {}
所有这一切都说: 做一些事情,如果出了问题,那就默默地失败了 。 这绝不是正确的事情:如果有问题,你想知道它,而不是疯狂地冲上去,好像什么也没发生过一样。 要么在catch
块中进行一些合理的处理,要么没有try
/ catch
并向方法签名添加throws IOException
,以便它可以向上传播。
但此刻,你只是在地毯下扫地。
ClassLoader.getResourceAsStream()
加载资源,就像加载类一样。 因此,它从运行时类路径加载它们。 不是来自项目中的源目录。
你的类Main
在包maintest
,因此它的名字是maintest.Main
。 我知道甚至没有看到代码,因为Main.java
位于名为maintest
的目录下,该目录位于源目录的正下方。
persistence.properties文件直接位于源目录( src/test/resources
)下。 在运行时,它是默认包中类路径的根。 它的名称是persistence.properties,而不是src/test/samples/peristence.properties
。 所以代码应该是
getClass().getClassLoader().getResourceAsStream("persistence.properties");
从samples目录中无法加载任何内容,因为此目录不在任何源目录下,因此不会由Eclipse编译,因此不可用于ClassLoader。
您的IDE使用两个不同的范围:
- 生产范围:src / main / java + src / main / resources文件夹和
- 测试范围:src / test / java + src / test / resources
似乎您正在尝试从生产范围执行程序,而persistence.properties文件则放入测试范围。
怎么修:
- 将测试放入src / test / java或
- 将persistence.properties移动到src / main / resources中