How to access file in the static resources(WEB-INF) folder from the referencing java project?

22,579

Solution 1

I ended up using Spring MockServletContext class and injecting it directly to my service bean, before the test runs, as my service implemented ServletContextAware :

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/test-ctx.xml" } ) 
public class SomeServiceTest {

@Autowired
private MyServletContextAwareService myService;

@Before
public void before(){
            //notice that I had to use relative path because the file is not available in the test project
    MockServletContext mockServletContext = new MockServletContext("file:../<my web project name>/src/main/webapp"); 

    myService.setServletContext(mockServletContext);        
}

If I had several classes using Servlet Context, then the better solution would be to use WebApplicationContext instead the default one (currently provided by DelegatingSmartContextLoader), but it would require implementing custom ContextLoader class and passing its class name to @ContextConfiguration annotation.

alternative and somewhat cleaner solution which later came to my mind is to refactor the service and inject ServletContext via @Autowired instead of messing with ServletContextAware, and provide the bean of corresponding type(effectively a MockServletContext instance).

Possibly, in future the direct support of MockServletContext from test classes will be added to Spring see SPR-5399 and SPR-5243.

UPDATE FOR SPRING 3.2 In Spring 3.2 initialization of the servlet context became as simple as adding one @WebAppConfiguration annotation:

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration("file:../<my web project name>/src/main/webapp")
@ContextConfiguration(locations = { "/test-ctx.xml" } ) 
public class SomeServiceTest {

see details in the article

Solution 2

Definitely keep the file under WEB-INF/ folder if that's where it is supposed to live.

For your test classes that are being executed from the command line. Your can use getClassLoader().getResource() on a file that you know is in the root of your classpath (e.g. application.properties file). From there you know the structure of your project and where to find WEB-INF/ relative to the properties file. Since it returns a URL you can use it to figure out a path to the XML files you're looking for.

URL url = this.getClass().getClassLoader().getResource("application.properties");
System.out.println(url.getPath());

File file = new File(url.getFile());
System.out.println(file);

// now use the Files' path to obtain references to your WEB-INF folder

Hopefully you find this useful. I have had to make assumptions about how your test classes are runing etc.

Take a look at the File Class and it's getPath(), getAbsolutePath(), and getParent() methods that could be of use to you.

Solution 3

In a Maven project I had same problem. I had no servletContext and couldn't access static file in WEB-INF directory. I came across to a solution by adding entry to pom.xml which gave me access to the directory. It actually includes this path to the classpath.

PS: I was using Tomcat container

<project>
    <build>
    <resources>
        <resource>
            <directory>src/main/webapp/WEB-INF</directory>
        </resource>
    </resources>
</project>

Solution 4

It's a classpath resource, so put it on the classpath: $webapp/WEB-INF/classes

Maven projects will copy things in $module/src/main/resources to this location when packaging the webapp. (the former is a sourcepath, the latter - WEB-INF/classes - is always put on the classpath by the servlet container, per spec.)

Share:
22,579
Boris Treukhov
Author by

Boris Treukhov

I am senior Java Developer in Moscow, my responsibilities are application architecture and microservice development in cloud with Spring and Kotlin.

Updated on July 05, 2022

Comments

  • Boris Treukhov
    Boris Treukhov almost 2 years

    I have a web application, that contains a configuration xml file for one of my application services that is exposed as spring bean. Also I have a standalone java application(which references my web app project from its pom.xml) in the same workspace, that runs tests using Spring TestContext framework and one of the tests checks the configuration of that XML file.

    However I have a problem with accessing this xml file from the standalone app:

    Before setting-up the test, in my previous configuration, the file was accessed through ServletContext and was located in WEB-INF/ folder. However, to make it accessable from the test project I had to move it to source/ folder and load it with getClassLoader().getResourceAsStream() method instead that of ServletContext. But it makes editing the file cumbersome because every time the app has to be redeployed.

    Is it possible to keep the file in WEB-INF/ folder but load it from the referencing project during the test-runs?

    P.S. Currently it's an STS project with Tomcat server.