I am not that experienced with maven. I am still learning and right now I am trying to do a simple project that will build for different environments populating different paths (I am also getting some guidance from chatGPT).
This is the simple structure:
My java file:
package com.example;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class MyApp {
public static void main(String[] args) {
try {
Properties props = new Properties();
InputStream stream = MyApp.class.getResourceAsStream("/application.properties");
props.load(stream);
stream.close();
System.out.println("Path: " + props.getProperty("path.oldscores"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
and the pom:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>my-app</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>copy-resources</id>
<phase>package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}</outputDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.example.MyApp</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>dev</id>
<properties>
<oldscores>/Users/Eclipse Workspace/TEST/my-app/oldscores.txt</oldscores>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<env>prod</env>
</properties>
</profile>
<profile>
<id>test</id>
<properties>
<env>test</env>
</properties>
</profile>
</profiles>
</project>
If I build it "mvn clean install -Pdev" I see that the application.properties in the outputDirectory specified gets populated:
my problem is with this line from my java file:
InputStream stream = MyApp.class.getResourceAsStream("/application.properties");
to my understanding we are still invoking the application.properties from the root (which is also confusing me because /application.properties would mean that this file is in the same location as where the pom is. If I execute this java file with this configuration I get:
Path: ${oldscores}
it is calling the application.properties from src/main/resources:
If I change it to:
InputStream stream = MyApp.class.getResourceAsStream("/target/application.properties");
which to me makes sense since now we are looking in root -> target -> and the properties file, I get:
Please help me understand where my confusion is and how I can extract the properties that get populated in the target folder or if this is even the correct way of doing this.
Thanks!
Class#getResourceAsStream
is loading resources from the class loader (where MyApp
is loaded from).
If you include a leading /
, it will look up the resources from the classpath root (or classloader root), which would be target/classes
(where classes and resources are copied to) or src/main/resources
. This does NOT refer to your project root.
In order to fix it, you could try to tell Maven to move the application.properties
to target/classes
(where it would normally be moved to):
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>copy-resources</id>
<phase>package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.outputDirectory}</outputDirectory><!-- alternative: ${project.build.directory}/classes -->
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
Resources will also be part of the application when you package it (e.g. in a JAR).
Alternatively, If you want to access files from where you are executing the project, you can use APIs for dealing with files:
Path path=Path.of("application.properties");
try(InputStream is=new BufferedInputStream(Files.newInputStream(path)){
//use is here
}
But be warned that this approach would require the file to be present when packaging the application and it will not include anything from inside the application.