пн, 20 апр. 2026 г. в 20:12, Christopher Schultz <[email protected]>:
>
> All,
>
> I just observed something in production that caused all kinds of weirdness.
>
> java.lang.NullPointerException: Cannot invoke
> &quot;java.io.File.toURI()&quot; because &quot;base&quot; is null
> org.apache.jasper.JspCompilationContext.createOutputDir(JspCompilationContext.java:676)
>     at
> org.apache.jasper.JspCompilationContext.getOutputDir(JspCompilationContext.java:196)
>     at
> org.apache.jasper.JspCompilationContext.getClassFileName(JspCompilationContext.java:530)
>     at org.apache.jasper.compiler.Compiler.isOutDated(Compiler.java:441)
>     at org.apache.jasper.compiler.Compiler.isOutDated(Compiler.java:412)
>     at
> org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:584)
>     at
> org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:379)
>     at
> org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:356)
>     at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:307)
>     at javax.servlet.http.HttpServlet.service(HttpServlet.java:623)
>
>
> It looks like the value of javax.servlet.context.tempdir became null at
> some point.

Hi, Chris!

Looking at the code (e.g. in Tomcat 11),
1) the "base" in org.apache.jasper.JspCompilationContext.createOutputDir
is "File base = options.getScratchDir();"

2) the "options" in org.apache.jasper.servlet.JspServlet.init() are
            // Use the default Options implementation
            options = new EmbeddedServletOptions(config, context);
(Those can be reconfigured to use a custom class, but it is unlikely
that you use that.)

3) org.apache.jasper.EmbeddedServletOptions constructor validates the value
and logs with "fatal" severity if the value is null or not an existing
directory:

        if (scratchDir == null) {
            log.fatal(Localizer.getMessage("jsp.error.no.scratch.dir"));
            return;
        }

        if (!(scratchDir.exists() && scratchDir.canRead() &&
scratchDir.canWrite() && scratchDir.isDirectory())) {
            log.fatal(Localizer.getMessage("jsp.error.bad.scratch.dir",
scratchDir.getAbsolutePath()));
        }

BTW, seeing a "return" above is odd, as this is in a constructor and
thus it skips processing of all other configuration options.

The scratchDir field in EmbeddedServletOptions is final, so there is
no way to change it afterwards, so you should have seen the log
message from EmbeddedServletOptions constructor.

4) Looking at o.a.c.core.StandardContext.postWorkDirectory()

        if (!dir.mkdirs() && !dir.isDirectory()) {
            log.warn(sm.getString("standardContext.workCreateFail",
dir, getName()));
        }
        ...
        context.setAttribute(ServletContext.TEMPDIR, dir);
        context.setAttributeReadOnly(ServletContext.TEMPDIR);

The "dir" in a "dir.mkdirs()" call cannot be null, and the last line
prevents further changes to the value.
Thus my question about a stray "return" in point 3) becomes moot, as
it should not happen.

Yet you saw something.

May it be that you are using some framework that mocks, wraps,
"instruments" the mentioned classes?
All is odd, given that the srratchDir field in EmbeddedServletOptions is final.

(A weirdness similar to an issue with JavaMelody, whatever that tool
is. E.g. oct 2025:
https://lists.apache.org/thread/v40g4opbcgs2s5ncdsl5qwg1l720oyfx

What is your version of Tomcat?
Any other oddities in the logs?
Were there context starts/stops/restarts at the same time?

Best regards,
Konstantin Kolinko

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to