getResourceAsStream not working all the time

I have a strange problem, and it been showing up intermittently for over a year.

I create a set of files as compile time in src/main/resources and read them at run time. Most of the time I have no problem with this, either when deployed on the robot or when run in the desktop simulator. However, under certain circumstances, the resource is not found in the simulator. I haven’t seen it happen on the RoboRio.

So, files in the resources directory are supposed to get included in the jar file for the application, and I have verified that they are, even when the getResourcesAsStream fails. The intermittent nature of the problem has made it extremely difficult to debug, but I finally have a test case that seems to be one hundred percent repeatable, on multiple systems.

First, clone the github repo (or fork if you want to futz with it. The problem follows the fork) GitHub - blu28/ChargedUp2023

Then, do the following exactly:
Let the initial clone and initialization complete.
Switch the local branch from “main” to “testbranch”
In a terminal window run “./gradlew spotlessApply”
The above task will cause three files to be modified, although doing a compare will show nothing changed (!).
Run WPILIB: Build Robot Code
Run WPILIB: Simulate Robot Code.
Select “SimGUI” as the type.

When the simulation runs, it will quit with an uncaught null pointer exception:

Error at frc.robot.Splash.printStatusFile(Splash.java:61): Unhandled exception: java.lang.NullPointerException: Cannot invoke "java.io.InputStream.read(byte[])" because "statusfile" is null 
        at frc.robot.Splash.printStatusFile(Splash.java:61)
        at frc.robot.Splash.printAllStatusFiles(Splash.java:31)
        at frc.robot.Robot.robotInit(Robot.java:37)
        at edu.wpi.first.wpilibj.TimedRobot.startCompetition(TimedRobot.java:106)
        at edu.wpi.first.wpilibj.RobotBase.runRobot(RobotBase.java:349)
        at edu.wpi.first.wpilibj.RobotBase.lambda$startRobot$0(RobotBase.java:422)
        at java.base/java.lang.Thread.run(Thread.java:833)

The code where this is failing looks like this:

try (InputStream statusfile =
        (Boolean.TRUE.equals(isResource))
            ? Main.class.getResourceAsStream("/" + filename)
            : new BufferedInputStream(new FileInputStream(filepath))) {

      System.out.print((filename + ": ").replace(".txt", ""));

      try {
        for (int length = 0; (length = statusfile.read(buffer)) != -1; ) {

The read is throwing the exception because statusfile is null. The “Main.class.getResourceAsStream” call has returned null trying to open the resource “/buildtime.txt”.

This is where it gets weird. If you look at the jar file under build/libs, the jar file has the correct file buildtime.txt as a member, right where it is supposed to be. You can re-run the build and re-run the simulate tasks all you like and it will still fail. But if you use the “Change Desktop Enabled Setting” to set it to disabled and then do it again to enable it again, then the problem goes away and I can’t get it to happen again.

I am at a loss. The same code is there in both cases, the resource is there in both cases. I just can’t figure out what is causing the problem. I guess there is some clean step I am missing when switching between branches. Is there a “proper” procedure for that?

Running sim in vscode doesn’t actually use the jar file. The vscode java extension actually does its own build. Are you using static resources, or are you generating them. Generating them might not always get picked up properly by vs code.

The run buttons on main in vscode does it even differently

It’s a bit of a weird setup, that works for stock builds but definitely starts breaking when more custom stuff works. If you want something that always runs the same way, you can just run ./gradlew simulateJava from the command prompt. You won’t have debugging support, but everything should use the jar and be correct.

The reason changing desktop works is it changes build.gradle, which forces a reload. This is kind of a tell that you’re not generating in a way that is always picked up by the vscode extension. You should be able to get back to this state by running a gradlew clean, deleting your resources and then calling clean Java workspace in vs code.

There’s actually probably another way to solve this. Place just any file in src/main/resources, and make sure that file gets committed. That will make the extension think there are resource files by default, and it should then look for changes in that folder.

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.