1

I'm confused how java sees the filesystem from the perspective of the classloader.

Let's say I have a jar file in EAR's APP-INF/lib folder. This jar file contains a class, which instantiates new File("foo.txt"). Also, the foo.txt is located in the APP-INF/lib folder next to jar.

Then, I'm using this library in WAR module. Now, will the code still find the file, or does it except it to be found in the EAR's root or WAR's root?

Tuomas Toivonen
  • 21,690
  • 47
  • 129
  • 225
  • 1
    For your `new File("foo.txt")` to work, the file needs to be in the current working directory. To load data from within the classpath, use `Classloader#getResourceAsInputStream`. Not sure how that works within an EAR, though. The classpaths for the different parts may be separated and not directly accessible to each-other. – Thilo Oct 05 '17 at 06:54
  • 2
    Indeed. In all the appservers I know, a straightforward file operation is independent of class loader behaviour. The class loader simply doesn't enter the picture. So, as @Thilo says, a filename is resolved relative to the appserver process current working directory, whatever that is. Some appservers set a specific CWS, some do not. Because of this, it's often better to user resource loading, rather than direct file loading, where practicable. Then you _do_ have to consider class loader behaviour, and the rules about where the various class loaders look are set out in the JEE specs. – Kevin Boone Oct 05 '17 at 08:06

2 Answers2

1

I am pretty sure that the file needs to be in WAR's root because WAR loads in your jarfile from EAR's APP-INF/lib thus it will search relative to WAR's filepath

This is an example how it is handled in the classpath

package main;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

public class Test {

    private Test() {
        Class<?> c = this.getClass();
        ClassLoader cl = c.getClassLoader();
        InputStream[] iss = new InputStream[8];
        URL[] urls = new URL[8];
        iss[0] = c.getResourceAsStream("/resources/txtFile.txt");
        iss[1] = c.getResourceAsStream("resources/txtFile.txt");
        iss[2] = c.getResourceAsStream("/txtFile.txt");
        iss[3] = c.getResourceAsStream("txtFile.txt");
        iss[4] = cl.getResourceAsStream("/resources/txtFile.txt");
        iss[5] = cl.getResourceAsStream("resources/txtFile.txt");
        iss[6] = cl.getResourceAsStream("/txtFile.txt");
        iss[7] = cl.getResourceAsStream("txtFile.txt");
        urls[0] = c.getResource("/resources/txtFile.txt");
        urls[1] = c.getResource("resources/txtFile.txt");
        urls[2] = c.getResource("/txtFile.txt");
        urls[3] = c.getResource("txtFile.txt");
        urls[4] = cl.getResource("/resources/txtFile.txt");
        urls[5] = cl.getResource("resources/txtFile.txt");
        urls[6] = cl.getResource("/txtFile.txt");
        urls[7] = cl.getResource("txtFile.txt");
        for (int i = 0; i < 8; i++)
            System.out.println("iss[" + i + "] is "
                    + String.valueOf(iss[i] == null));
        for (int i = 0; i < 8; i++)
            System.out.println("url[" + i + "] is "
                    + String.valueOf(urls[i] == null));

    }

    public static final void main(String[] args) {
        new Test();
    }
}

Prints

iss[0] is false
iss[1] is true
iss[2] is true
iss[3] is true
iss[4] is true
iss[5] is false
iss[6] is true
iss[7] is true
url[0] is false
url[1] is true
url[2] is true
url[3] is true
url[4] is true
url[5] is false
url[6] is true
url[7] is true
Dinh
  • 759
  • 5
  • 16
  • This might be true when loading _resources_, but the OP specifically asks about `File` objects, not resources. – Kevin Boone Oct 05 '17 at 08:03
  • Did you read the top of my post? the bottom was just some extra – Dinh Oct 05 '17 at 08:04
  • 2
    Yes, I read it. I believe your answer is incorrect, so far as the OP's question is concerned. Class loader behaviour has no bearing on _File_ loading in JEE-compliant appservers, only on resource loading. Arguably the OP should be specifying his data files as resources, not `File`s, but he isn't. If I have misunderstood what you wrote, I apologise. – Kevin Boone Oct 05 '17 at 08:11
1

You cannot rely on being able to access anything in an EAR file deployment as a java.io.File object.

Java EE servers are not required to "explode" deployments in the file system and many will not. Some vendors may provide the option to do this but in general it's not wise to depend upon this capability.

Furthermore, plain files built into an EAR file become completely inaccessible using a class loader.

Within an EAR file objects can only be accessed from a class loader if they are inside an EAR/lib jar file, an EJB module, RAR module or WEB module (WAR). Even then there are rules regarding what modules can see in other modules, as described in the answer to My ear is not able to find ejb module classes

That said, your question is referring to a non-standard APP-INF/lib directory. You would need to refer to your vendor documentation to discover what that enables. I vaguely recall it being a precursor to the standardisation of the EAR/lib mechanism (in Java EE 5 in 2009) in either WebLogic or WebSphere.

Steve C
  • 18,876
  • 5
  • 34
  • 37