Programmatically getting the Maven version of your project - java

How do I get the Maven version of my project programatically?
In other words:
static public String getVersion()
{
...what goes here?...
}
For example, if my project would generate the jar CalculatorApp-1.2.3.jar, I want getVersion() to return 1.2.3.

Create file version.prop in src/main/resources with the following contents:
version=${project.version}
Add the following to your project's pom:
<build>
...
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/version.prop</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
<excludes>
<exclude>**/version.prop</exclude>
</excludes>
</resource>
</resources>
...
</build>
Add the following method:
public String getVersion()
{
String path = "/version.prop";
InputStream stream = getClass().class.getResourceAsStream(path);
if (stream == null)
return "UNKNOWN";
Properties props = new Properties();
try {
props.load(stream);
stream.close();
return (String) props.get("version");
} catch (IOException e) {
return "UNKNOWN";
}
}
p.s. Found most of this solution here: http://blog.nigelsim.org/2011/08/31/programmatically-getting-the-maven-version-of-your-project/#comment-124

For jar files, you have the MANIFEST.MF as the default place to put the Implementation-Version there. Maven supports building the jar file like this.
See also
How do I add an Implementation-Version value to a jar manifest using Maven?

Related

StreamCorruptedException only in a Spring Boot application

On a Spring Boot application (2.3.3), I have a dependency to a module developed by my company. From a service I'm calling a method from this dependency which needs a file loaded from resources (src/main/resources/META-INF/spring-main-cfg.xml), so I've copied and pasted this file to my Spring Boot application resources.
Here's the code executed in that dependency:
InputStream in = RSAEncrypter.class.getClassLoader().getResourceAsStream(keyFileName);
// StreamCorruptedException here
ObjectInputStream oin = new ObjectInputStream(new BufferedInputStream(in));
Stack:
java.io.StreamCorruptedException: invalid stream header: EFBFBDEF
at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:936) ~[na:1.8.0_281]
at java.io.ObjectInputStream.(ObjectInputStream.java:394) ~[na:1.8.0_281]
The thing is, I've created a new dummy Maven project with only this dependency and a main to execute that code and it works.
I don't understand what could be the reasons I've got this exception executed from my Spring Boot application. I've got the same Java version, the file read is the same.
Any ideas?
I've finally found the issue, it was the file it self since I had a global:
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
The Maven doc on this say:
Warning: Do not filter files with binary content like images! This will most likely result in corrupt output.
https://maven.apache.org/plugins/maven-resources-plugin/examples/filter.html
So I just added an exception for my file :
<resources>
<!-- Only properties files have to be filtered.
META-INF/spring-main-cfg.xml must not be or StreamCorruptedException occure by reading it -->
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/*.properties</include>
</includes>
</resource>
</resources>

Wrong content of binary test resources when using ClassLoader InputStream

I have a binary file in test resources src/test/resources/file.bin:
$ ls -la src/test/resources
-rw-r--r-- 1 g4s8 g4s8 5125 Apr 30 19:53 file.bin
I'm using it for tests to verify some class.
Before testing, I need to copy the content to the file-system, I'm using Thread.currentThread().getContextClassLoader() to read the data:
#Test
public void readsContent(#TempDir final Path tmp) throws Exception {
final ClassLoader clo = Thread.currentThread().getContextClassLoader();
final Path file = Files.createFile(tmp.resolve("file.bin"));
try (
final InputStream res = new BufferedInputStream(clo.getResourceAsStream("file.bin"));
final OutputStream out = new BufferedOutputStream(Files.newOutputStream(file, StandardOpenOption.CREATE, StandardOpenOption.WRITE))
) {
byte[] buf = new byte[8192];
for (int read = res.read(buf); read >= 0; read = res.read(buf)) {
out.write(buf, 0, read);
}
}
// test code
}
But the content of this file is bigger than expected and it differ from what was in resource file:
$ ls -la /tmp/junit18423574017636618834/
-rw-r--r-- 1 g4s8 g4s8 9350 May 1 12:22 file.bin
The result file is 9350 bytes of size, but source file was 5125.
With hex editor I investigated that only first two bytes of these files are the same, all other data is different:
What's wrong with my code? Why this file can't be read correctly using standard way via ClassLoader?
It was caused by enabled filtering Maven option inherited from parent pom.xml, it seems Maven managed to find and replace some patterns in binary file, and IDE uses Maven to prepare test resources:
<build>
<resources>
<resource>
<directory>${basedir}/src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<testResources>
<testResource>
<directory>${basedir}/src/test/resources</directory>
<filtering>true</filtering>
</testResource>
</testResources>
</build>
I've overridden this option in project's pom.xml, and it's working now:
<build>
<testResources>
<testResource>
<directory>${basedir}/src/test/resources</directory>
<filtering>false</filtering>
</testResource>
</testResources>
</build>

How to get all resources inside a resource directory in a JAR file?

I'm using Spring Boot and I want to get resources.
Here's my directory structure:
├───java
│ └───...
├───resources
│ └───files
│ ├───file1.txt
│ ├───file2.txt
│ ├───file3.txt
│ └───file4.txt
I'm trying to get the resources in the files directory. Here's what I've done to access these files:
#Autowired
private ResourceLoader resourceLoader;
...
Stream<Path> walk = Files.walk(Paths.get(resourceLoader.getResource("classpath:files/").getURI()));
This works running locally when the files are in the target directory, but the files are not found when I run it from a JAR file. How do I fix this? I've checked that these files do exist in the jar located under BOOT-INF/classes/files.
Here's how maven is building and copying the resources into the JAR (I don't want the .txt files to be filtered):
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<excludes>
<exclude>**/*.txt</exclude>
</excludes>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
<includes>
<include>**/*.txt</include>
</includes>
</resource>
</resources>
Can you try with the following code to read the files ?
ResourcePatternResolver resourcePatResolver = new PathMatchingResourcePatternResolver();
Resource[] AllResources = resourcePatResolver.getResources("classpath*:files/*.txt");
for(Resource resource: AllResources) {
InputStream inputStream = resource.getInputStream();
//Process the logic
}
This is not the exact solution for the code you have written, but it will give an outline about the resources to read.
Someone else had the same issue as you and they found the solution by combining the ResourceLoader with the ResourcePatternResolver as Sambit suggested. See here for the same issue with answer: https://stackoverflow.com/a/49826409/6777695

Maven resource filtering of json file

In my current project I have a submodule which is using the maven exec plugin to run a test service which pulls configuration files from a location outside of the resources/testResources folders.
I need to use filtering to inject an environment variable into a few of the configuration files. This is working for one of the files, a .properties file, but not for another file which is a .json. In the latter case it simply leaves the variable in the json file. The two files are right next to each other in the filtered directory.
Here is the filtering snippet from the submodule:
<build>
<finalName>${artifactId}</finalName>
<testResources>
<testResource>
<filtering>true</filtering>
<directory>../etc</directory>
</testResource>
</testResources>
json file:
{ "customMappings" :
{ "tag:example.com:/vagrant/" : "file:${VAGRANT_CWD}" }
}
Abbreviated project structure:
project
etc
config.properties
config.json
submodule
pom.xml
The submodule is definitely loading both files, but only filtering the .properties file.
Is there something special about it being a json file that would prevent filtering from happening to it? Anything that can be done about this?
For what its worth, I did eventually get this to work. I found that I had to directly list the file for inclusion in order to get it to be processed (its been a long time so hopefully this is the correct solution):
<build>
<finalName>${artifactId}</finalName>
<testResources>
<testResource>
<filtering>true</filtering>
<directory>../etc</directory>
<includes>
<include>config.json</include>
<include>config.properties</include>
</includes>
</testResource>
</testResources>
...

Netbeans Platform: InstalledFileLocator

I added a resource for a module as follows:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>nbm-maven-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<moduleType>eager</moduleType>
<nbmResources>
<nbmResource>
<directory>${basedir}/resources</directory>
<targetPath>resources</targetPath>
<includes>
<include>*.db</include>
</includes>
<excludes>
<exclude>*trace*</exclude>
</excludes>
</nbmResource>
</nbmResources>
</configuration>
</plugin>
The file shows in the Netbeans application at: target/app name/app name/resources/card_manager.mv.db. That looks fine.
Now I'm trying to get that file location as follows:
File db = InstalledFileLocator.getDefault().locate("card_manager.mv.db",
"module.codename.base", false);
But db is always null. Any idea?
Try this code...
File file = InstalledFileLocator.getDefault().locate("myfile", null, false);
if (file == null)
{
file = new File(Places.getUserDirectory() + File. separator + "myfile");
}
Or have you tried resources/card_manager.mv.db? I'm sure the application path (app name) and cluster name (second app name) is excluded from locate() but I believe you have to include resources/ path.
Modify your pom so that the card_manager.mv.db is copied to the classes folder rather than the resources folder and fetch the file from your classloader.

Categories