2

I have been looking for a while for practical examples to understand Maven relative paths best practices to get Resources, however I got confused, hoping you could please support me to understand what are best practices to get Resources and how to apply to a concrete example:

Concrete Example:

Structure Say I have the following structure and trying to get a resource(located in resources) from a class in the folder planning, so basically I am trying to create a String of a relative path that is consistent with maven execution:

├───.settings
├───images
├───src
│   ├───main
│   │   ├───java
│   │   │   └───com
│   │   │       └───moga
│   │   │           ├───planning --->Trying to get a resource from here
│   │   │           ├───population
│   │   │           │   ├───chromossome
│   │   │           │   ├───gene
│   │   │           │   └───initialpopulation
│   │   │           └───utils
│   │   └───resources
│   │       └───com
│   │           └───moga
│   │               └───planning
│   │                   └───sample
│   └───test
│       ├───java
│       │   └───com
│       │       └───moga
│       │           ├───planning
│       │           └───population
│       │               ├───chromossome
│       │               └───gene
│       └───resources
│           └───com
│               └───moga
│                   └───planning <-- Resource that I want to get is here
│                       └───sample
└───target
    ├───classes
    │   └───com
    │       └───moga
    │           ├───planning
    │           │   └───sample
    │           ├───population
    │           │   ├───chromossome
    │           │   ├───gene
    │           │   └───initialpopulation
    │           └───utils
    ├───generated-sources
    │   └───annotations
    ├───generated-test-sources
    │   └───test-annotations
    ├───maven-archiver
    ├───maven-status
    │   └───maven-compiler-plugin
    │       ├───compile
    │       │   └───default-compile
    │       └───testCompile
    │           └───default-testCompile
    ├───surefire-reports
    └───test-classes
        └───com
            └───moga
                ├───planning
                │   └───sample
                └───population
                    ├───chromossome
                    └───gene

Class RunCapacityPlanning that gets the resource I am currently using the following quick fix

Path pathCapacityPlanningGeneral = Paths.get(System.getProperty("user.dir"),
        "src","test","resources","com","moga","planning","paramsGeneral.txt");
File file = new File(pathCapacityPlanningGeneral.toString());
if (!file.exists()) {
    System.out.println("File Do not exist");
    System.out.println(pathCapacityPlanningGeneral.toString());
}

The above code is builded with mvn package and the file exists(Do not print the message).

POM

...
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>
...

Approaches Here are some potential approaches I have found:

  1. Maven Official
    File file = new File( path );
    if ( !file.isAbsolute() )
    {
        file = new File( project.getBasedir(), file );
    }
    

To test this approach, here is what I tried:

From this I understand that I should add this to my POM

  <properties>
<project.basedir>somepath</project.basedir>
...
  </properties>

  • What should I add in this somepath? I have tested leaving somepath blank and trying to print in my class to understand, however it shows cannot be resolved.
public static void main(String[] args) throws IOException {
    // 1) Approach 1
    // $ cannot be resolved to a variable,
    // project cannot be resolved
    System.out.println(${project.baseDir});
  1. Use getResource Basically I tested modify the main file:
URL pathCapacityPlanningGeneral =
        RunCapacityPlanning.class.getResource("paramsGeneral.txt");
File file = new File(pathCapacityPlanningGeneral.toString());
if (!file.exists()) {
    System.out.println("File Do not exist");
    System.out.println(pathCapacityPlanningGeneral.toString());
}

The above after mvn package java -cp target/CapacityPlan-1.0-SNAPSHOT.jar com.moga.planning.RunCapacityPlanning throws:

File Do not exist
jar:file:/C:/Users/.../capacityplan/target/capacityplan-1.0-SNAPSHOT.jar!/com/moga/planning/paramsGeneral.txt

Do anybody knows what I am doing wrong in this approach?

Thanks so much in advance

dtkx
  • 105
  • 1
  • 8

1 Answers1

1

The Point here is:
The resources are resolved using the Class Path, and not along your project directory layout. This means that resource resolution start below
src/[main|test]/[java|resources]/

The best way to resolve a resource ist to look it up by

new File(getClass()
          .getResource("the resource relative path")
          .toURI()) 

This way it does not matter it that resource is in a plain directory or inside a jar.

"the resource relative path" can start with a /. In that case it is resolved relative to the CLASSPATH root. If it does not start wit / it is resolved relative to the current package.

In your example it the folder planning is what you want you could either use

// from package "planning" one level up
new File(getClass()
            .getResource("../plannung")
            .toURI()) 

or

// from CLASSPATH root decending
new File(getClass()
            .getResource("/com/moga/plannung")
            .toURI()) 

ATTENTION!

Always use forward slashes (/) in path names. Java handles them correctly on windows too.

Timothy Truckle
  • 15,071
  • 2
  • 27
  • 51
  • Thank you @Timothy, I tested the approach but as I am trying to get the resource from a static context, (given this [post] (https://stackoverflow.com/questions/53641486/how-to-solve-cannot-make-a-static-reference-to-the-non-static-method/53641534) . I have used the following File file = new File(RunCapacityPlanning.class.getResource("/com/moga/planning/paramsGeneral.txt").toURI());//compiles, but throws java.lang.IllegalArgumentException: URI is not hierarchical. – dtkx Jun 23 '21 at 16:13
  • I have found this [post](https://stackoverflow.com/questions/10144210/java-jar-file-use-resource-errors-uri-is-not-hierarchical). However as I try InputStream input = RunCapacityPlanning.class.getClassLoader().getResourceAsStream("/com/moga/planning/paramsGeneral.txt"); System.out.println("Available bytes in the file: " + input.available());//prompts a "java.lang.NullPointerException). I think i might be missing something or overcomplicating. – dtkx Jun 23 '21 at 16:19
  • 1
    `RunCapacityPlanning.class.getClassLoader().getResourceAsStream()` behaves different than `RunCapacityPlanning.class.getResourceAsStream()`! – Timothy Truckle Jun 23 '21 at 16:41
  • 1
    *"as I am trying to get the resource from a static context"* **--** you can assign the resource from a *static initializer*. Of cause the class variable cannot be `final` in that case... – Timothy Truckle Jun 23 '21 at 16:44
  • Thank you, I did not notice the difference. Just to make sure I understood, by assigning the resource from a static initializer you mean this RunCapacityPlanning.class.getResource("/com/moga/planning/paramsGeneral.txt").toURI()), right? Would you suggest another alternative to the Exception raised java.lang.IllegalArgumentException: URI is not hierarchical? – dtkx Jun 24 '21 at 12:46
  • see second section here: https://docs.oracle.com/javase/tutorial/java/javaOO/initial.html – Timothy Truckle Jun 24 '21 at 16:54