Question

I am using maven and the standard directory layout. So I have added a testdata.xml file in the src/test/resources folder, and I also added it as:

.addAsWebInfResource("testdata.xml", "testdata.xml")

in the deployment method, and I have confirmed that it is there. This will make the file appear in /WEB-INF/testdata.xml. Now I need to have a reference to this file in my code and I tried several different getClass().getResourceAsStream(...) and failing again and again so I need some advise now.

I need it for my DBUnit integration test. Is this not possible?

Was it helpful?

Solution

Option A) Use ServletContext.getResourceXXX()

You should have a Aquillarian MockHttpSession and a MockServletContext. E.g.:

@Test
   public void myTest()
   {
      HttpSession session = new MockHttpSession(new MockServletContext());
      ServletLifecycle.beginSession(session);

      ..testCode..

      // You can obtain a ServletContext (will actually be a MockServletContext 
      // implementation):
      ServletContext sc = session.getServletContext();
      URL url = sc.getResource("/WEB-INF/testdata.xml")
      Path resPath = new Path(url);
      File resFile = new File(url);
      FileReader resRdr = new FileReader(resFile);
      etc...

      ..testCode..

      ServletLifecycle.endSession(session);
   }

You can create resource files & subdirectories in:

  1. the web module document root - resources are accessible from the browser and from classes
  2. WEB-INF/classes/ - resources are accessible to classes
  3. WEB-INF/lib/*.jar source jar - accessible to classes
  4. WEB-INF/lib/*.jar dedicated resource-only jar - accessible to classes
  5. WEB-INF/ directly within directory - accessible to classes. This is what you are asking for.

In all cases the resource can be accessed via:

URL url = sc.getResource("/<path from web doc root>/<resourceFileName>");
OR    
InputStream resIS = sc.getResourceAsStream("/<path from web doc root>/<resourceFileName>");

>

These will be packaged into the WAR file and may be exploded into directories on the deployed app server OR they may stay within the WAR file on the app server. Either way - same behaviour for accessing resources: use ServletContext.getResourceXXX().

Note that as a general principle, (5) the top-level WEB-INF directory itself is intended for use by the server. It is 'polite' not to put your web resources directly in here or create your own directory directly in here. Instead, better to use (2) above.

JEE5 tutorial web modules JEE6 tutorial web modules

Option B): Use Class.getResourceXXX()

First move the resource out of WEB-INF folder into WEB-INF/classes (or inside a jar WEB-INF/lib/*.jar).

If your test class is:

  • com.abc.pkg.test.MyTest in file WEB-INF/classes/com/abc/pkg/test/MyTest.class

And your resource file is

  • WEB-INF/classes/com/abc/pkg/test/resources/testdata.xml (or equivalent in a jar file)

Access File using Relative File Location, via the Java ClassLoader - finds Folders/Jars relative to Classpath:

java.net.URL resFileURL = MyTest.class.getResource("resources/testdata.xml");
File resFile = new File(fileURL);    
OR
InputStream resFileIS = 
     MyTedy.class.getResourceAsStream("resources/testdata.xml");

Access File Using full Package-like Qualification, Using the Java ClassLoader - finds Folders/Jars relative to Classpath:

java.net.URL resFileURL = MyTest.class.getResource("/com/abc/pkg/test/resources/testdata.xml");
File resFile = new File(fileURL);        
OR 
InputStream resFileIS = 
     MyTest.class.getResourceAsStream("/com/abc/pkg/test/resources/testdata.xml");   
OR 
java.net.URL resFileURL = MyTest.class.getClassLoader().getResource("com/abc/pkg/test/resources/testdata.xml");
File resFile = new File(fileURL);       
OR 
InputStream resFileIS = 
     MyTest.class.getClassLoader().getResourceAsStream("com/abc/pkg/test/resources/testdata.xml");

Hope that nails it! @B)

OTHER TIPS

The way to access files under WEB-INF is via three methods of ServletContext:

  1. getResource("/WEB-INF/testdata.xml") gives you a URL
  2. getResourceAsStream gives you an input stream
  3. getRealPath gives you the path on disk of the relevant file.

The first two should always work, the third may fail if there is no direct correspondence between resource paths and files on disk, for example if your web application is being run directly from a WAR file rather than an unpacked directory structure.

Today I was struggling with the same requirement and haven't found any full source sample, so here I go with smallest self contained test I could put together:

@RunWith(Arquillian.class)
public class AttachResourceTest {

    @Deployment
    public static WebArchive createDeployment() {
        WebArchive archive =  ShrinkWrap.create(WebArchive.class).addPackages(true, "org.apache.commons.io")
                .addAsWebInfResource("hello-kitty.png", "classes/hello-kitty.png");             
        System.out.println(archive.toString(true));
        return archive;
    }

    @Test
    public void attachCatTest() {
        InputStream stream = getClass().getResourceAsStream("/hello-kitty.png");
        byte[] bytes = null;
        try {
            bytes = IOUtils.toByteArray(stream);
        } catch (IOException e) {
            e.printStackTrace();
        }   
        Assert.assertNotNull(bytes);
    }
}

In your project hello-kitty.png file goes to src/test/resources. In the test archive it is packed into the /WEB-INF/classes folder which is on classpath and therefore you can load it with the same class loader the container used for your test scenario.

IOUtils is from apache commons-io.

Additional Note: One thing that got me to scratch my head was related to spaces in path to my server and the way getResourceAsStream() escapes such special characters: sysLoader.getResource() problem in java

Add this class to your project:

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;

public class Init {
    private static final String WEB_INF_DIR_NAME="WEB-INF";
    private static String web_inf_path;
    public static String getWebInfPath() throws UnsupportedEncodingException {
        if (web_inf_path == null) {
            web_inf_path = URLDecoder.decode(Init.class.getProtectionDomain().getCodeSource().getLocation().getPath(), "UTF8");
            web_inf_path=web_inf_path.substring(0,web_inf_path.lastIndexOf(WEB_INF_DIR_NAME)+WEB_INF_DIR_NAME.length());
        }
        return web_inf_path;
    }
}

Now wherever you want to get the full path of the file "testdata.xml" use this or similar code:

String testdata_file_location = Init.getWebInfPath() + "/testdata.xml";
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top