Skip to content

ServletContext getResourceAsStream for file in META-INF/resources does not work in an IDE, spring-boot:run, or bootRun #8525

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
davidmelia opened this issue Mar 7, 2017 · 12 comments
Assignees
Labels
type: bug A general bug
Milestone

Comments

@davidmelia
Copy link

davidmelia commented Mar 7, 2017

Hi,

I've just upgraded from Boot 1.5.1 to 1.5.2 and am now getting null back from getServletContext().getResourceAsStream. This happens in STS (3.8.3) only and not when running from the command line.

I've distilled the problem down into a simple project on Bit Bucket

My simple project consists of a WAR which contains a Servlet 'SomeServlet' which looks for a resource /scripts/lib/dave.js inside a dependent JAR /resources/META-INF/resources. If the resource is not found I throw an exception.
. Boot 1.5.1 works fine on both command line and in STS. Boot 1.5.2 works fine on the command line but breaks in Eclipse returning null.

Any ideas?

Thanks

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Mar 7, 2017
@wilkinsona
Copy link
Member

It may be this change that was made in 1.4.5 and 1.5.2.

When you say this it works fine when running from the command line, how are you running your application? Are you using mvn spring-boot:run or java -jar?

@wilkinsona wilkinsona added the status: waiting-for-feedback We need additional information before we can continue label Mar 7, 2017
@davidmelia
Copy link
Author

java -jar

@davidmelia
Copy link
Author

And interestingly mvn spring-boot:run causes the error as well.

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Mar 7, 2017
@juanpablo-santos
Copy link
Contributor

juanpablo-santos commented Mar 8, 2017

Hi,

attached another sample project that seems too reproduce this same issue, this time when trying to set up SiteMesh 2.

With 1.5.1, the file from $PROJECT/src/main/resources/META-INF/resources/WEB-INF/decorators.xml gets readed. With 1.5.2, we end up with the following stacktrace:

com.opensymphony.module.sitemesh.factory.FactoryException: Cannot construct Factory : com.opensymphony.module.sitemesh.factory.DefaultFactory: java.lang.IllegalStateException: Cannot load excludes configuration file "/WEB-INF/decorators.xml" as specified in "sitemesh.xml" or "sitemesh-default.xml"
at com.opensymphony.module.sitemesh.Factory.getInstance(Factory.java:50) ~[sitemesh-2.4.2.jar:na]
at com.opensymphony.sitemesh.webapp.SiteMeshFilter.initContentProcessor(SiteMeshFilter.java:107) ~[sitemesh-2.4.2.jar:na]
at com.opensymphony.sitemesh.webapp.SiteMeshFilter.doFilter(SiteMeshFilter.java:54) ~[sitemesh-2.4.2.jar:na]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.11.jar:8.5.11]

The line causing the issue involves one config.getServletContext().getResourceAsStream(.. returning null with 1.5.2.

(this happens when running app from console, no STS involved)

@juanpablo-santos
Copy link
Contributor

oh, and notice that we need org.apache.tomcat.embed:tomcat-embed-jasper in order to get the application running with 1.5.1. If that dependency is omitted, we get the same stacktrace as with 1.5.2.

@wilkinsona wilkinsona self-assigned this Mar 8, 2017
@wilkinsona
Copy link
Member

@davidmelia Thanks for the sample project and the details on how you're running the app. As I suspected, the problem was introduced by the changes for #8299.

Here's a work around:

@Bean
public TomcatEmbeddedServletContainerFactory tomcat() {
    TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory = new TomcatEmbeddedServletContainerFactory();
    tomcatEmbeddedServletContainerFactory.addContextCustomizers((context) -> {
        context.addLifecycleListener((event) -> {
            if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) {
                ClassLoader classLoader = getClass().getClassLoader();
                if (classLoader instanceof URLClassLoader) {
                    for (URL url: ((URLClassLoader)classLoader).getURLs()) {
                        if ("file".equals(url.getProtocol())) {
                            File file = new File(url.getFile());
                            if (file.isFile() || new File(file, "META-INF/resources").isDirectory()) {
                                context.getResources().createWebResourceSet(ResourceSetType.RESOURCE_JAR, "/", url, "/META-INF/resources");
                            }
                        }
                    }
                }
            }
        });
    });
    return tomcatEmbeddedServletContainerFactory;
}

@wilkinsona wilkinsona added priority: high type: bug A general bug and removed status: feedback-provided Feedback has been provided status: waiting-for-triage An issue we've not yet triaged labels Mar 8, 2017
@wilkinsona wilkinsona added this to the 1.4.6 milestone Mar 8, 2017
@wilkinsona wilkinsona changed the title Boot 1.5.2 breaks servletContext getResourceAsStream when running in STS 3.8.3 ServletContext getResourceAsStream for file in META-INF/resources does not work in an IDE, spring-boot:run, or bootRun Mar 9, 2017
@wilkinsona
Copy link
Member

@juanpablo-santos Your sample project fails for me with both 1.5.1 and 1.5.2. That's actually what I would expect as, per the servlet spec, loading content from META-INF/resources is only supported for nested jars. #8324 is tracking the possibility of changing that.

@wilkinsona
Copy link
Member

a2cf045 should have referenced this issue.

@juanpablo-santos
Copy link
Contributor

Hi @wilkinsona,

thanks for looking into the sample. In it, with 1.5.2, http://localhost:8080/index.html gets you the "Whitelabel Error Page", with the underlying exception being:

There was an unexpected error (type=Internal Server Error, status=500).
Cannot construct Factory : com.opensymphony.module.sitemesh.factory.DefaultFactory: java.lang.IllegalStateException: Cannot load excludes configuration file "/WEB-INF/decorators.xml" as specified in "sitemesh.xml" or "sitemesh-default.xml"

This is caused because config.getServletContext().getResourceAsStream(.. is returning null inside Sitemesh.

With 1.5.1, the same URL gets another "Whitelabel Error Page", but this time the underlying exception is:

There was an unexpected error (type=Not Found, status=404).
No message available

which is expected as Sitemesh decorator itself is a blank page, there aren't any controllers, etc. But the former line is able to locate the decorators file inside [src/main/resources/]META-INF/resources as config.getServletContext().getResourceAsStream(.. doesn't return null anymore. (Sitemesh templates don't need to be static resources, they could also be jsps, so maybe that's why they get readed from there - tomcat-embed-jasper is also lurking in there..).

In any case, applying the provided workaround with 1.5.2 also fixes the issue, so thanks for your prompt response! :-)

@juanpablo-santos
Copy link
Contributor

Hi,

found one corner case with the above solution, spring-boot maven plugin won't start if the project has a dependency of type pom, yielding the following exception:

java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Tomcat].StandardHost[localhost].TomcatEmbeddedContext[]]
        at java.util.concurrent.FutureTask.report(FutureTask.java:122) [na:1.8.0_112]
        at java.util.concurrent.FutureTask.get(FutureTask.java:192) [na:1.8.0_112]
        at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:939) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
        at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:872) [tomcat-embed-core-8.5.11.jar:8.5.11]
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) [tomcat-embed-core-8.5.11.jar:8.5.11]
[...]
Caused by: java.lang.IllegalArgumentException: The file specified by base and internal path [c:\java\.m2\repo\com\twelvemonkeys\bom\bom\3.3.2\bom-3.3.2.pom]\[/META-INF/resources] does not exist.
        at org.apache.catalina.webresources.FileResourceSet.checkType(FileResourceSet.java:172) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
        at org.apache.catalina.webresources.AbstractFileResourceSet.initInternal(AbstractFileResourceSet.java:145) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
        at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:107) [tomcat-embed-core-8.5.11.jar:8.5.11]

one possible quick fix is to substitue the innermost if above with:

if( ( file.isFile() && !file.getName().endsWith( ".pom" ) ) || new File( file, "META-INF/resources" ).isDirectory() ) {

@wilkinsona
Copy link
Member

@juanpablo-santos Thank you for trying the snapshot

@wilkinsona wilkinsona reopened this Mar 13, 2017
@wilkinsona
Copy link
Member

I've just realised the failure above wasn't with the fix in the snapshots, it's with the workaround I suggested above. The fix in the snapshots is more defensive.

Artur- added a commit to vaadin/bakery-app-starter-fw8-spring that referenced this issue Jun 6, 2017
Artur- added a commit to vaadin/bakery-app-starter-fw8-spring that referenced this issue Jun 6, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug A general bug
Projects
None yet
Development

No branches or pull requests

4 participants