Externalize properties for command line tool using spring boot - spring-boot

I wanted to do a very simple thing which I had already done, which is using a spring boot packaged jar with some custom properties (private.properties containing a token) provided in a "config" directory. Currently I'm using a recent version of Spring Boot ("2.2.5.RELEASE").
My "config" directory was never taken into account and I had to do 2 very unintuitive things :
Complete spring boot maven plugin conf like this :
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>${start-class}</mainClass>
<layout>ZIP</layout>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
and add these properties :
java -Dloader.home=. -Dloader.path=config -Dloader.config.name=private -jar my.jar
Could someone please tell me where is it officially documented (both actions) ? Is there a more simple way of doing this with less explicit parameters ?

Here is the answer :
"ZIP (alias to DIR): similar to the JAR layout using PropertiesLauncher."
source : https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/html/#repackage
and :
"PropertiesLauncher is a launcher for archives with user-configured classpath and main class via a properties file. This model is often more flexible and more amenable to creating well-behaved OS-level services than a model based on executable jars.
Looks in various places for a properties file to extract loader settings, defaulting to loader.properties either on the current classpath or in the current working directory. The name of the properties file can be changed by setting a System property loader.config.name (e.g. -Dloader.config.name=foo will look for foo.properties. If that file doesn't exist then tries loader.config.location (with allowed prefixes classpath: and file: or any valid URL). Once that file is located turns it into Properties and extracts optional values (which can also be provided overridden as System properties in case the file doesn't exist):
loader.path: a comma-separated list of directories (containing file resources and/or nested archives in *.jar or *.zip or archives) or archives to append to the classpath. BOOT-INF/classes,BOOT-INF/lib in the application archive are always used
loader.main: the main method to delegate execution to once the class loader is set up. No default, but will fall back to looking for a Start-Class in a MANIFEST.MF, if there is one in ${loader.home}/META-INF.
"
source : https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/loader/PropertiesLauncher.html

Related

Spring Native custom name for generated executables

I want to change the name of the generated executables in Spring Native with Maven.
Default is the <artifactId> from the pom.xml.
If we want to specify the name of the resulting .jar file, we have an option to configure this with <finalName> inside the spring-boot-maven-plugin plugin configuration.
Is there a similar configuration property to allow the same behavior for the native-image-plugin?
I just found a solution using <imageName> inside the native-image-plugin configuration like:
pom.xml (only part of file shown)
...
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
<configuration>
<imageName>app</imageName>
</configuration>
...

More elegant way to define a flexible application configuration in spring boot

I want a spring boot app that has a flexibility to use the default embedded configuration files; but also has a flexibility to be able to override it with an external configuration files.
During debugging, I wish it to uses the embedded property file inside the jar file. But during deployment, I want it to use the external application.yml so I can customize values on production.
I tried a lot of forum but there seems to be no other way out of this. Does this give priority to the embedded one and overwrite it
#PropertySources({
#PropertySource("classpath:application.yml"),
#PropertySource(value = "file:application.yml", ignoreResourceNotFound = true)
})
I manually moved the yml to be in target directory.
<!-- Copy the config to target -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>${maven.resource.plugin.version}</version>
<executions>
<execution>
<id>copy-resources</id>
<phase>validate</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${basedir}/target/</outputDirectory>
<resources>
<resource>
<directory>${basedir}/src/main/resources</directory>
<filtering>*.yml</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
The above seems able to work. But I am not sure if there is a more elegant way to do this. I have my doubts since the property source array did not seem to specify the priority, it may just work for now. Do we have another way to do this aside from how I did it?
Spring has profiles for this.
Spring boot can read from src/main/resources/application.properties (and config folder works as well) by default, however if you put property like this:
--spring.profiles.active=dev
It will also read stuff from /src/main/resources/application-dev.properties (suffix must match the profile). Yaml works like this as well.
So, this should cover the "development" mode.
Now, in a real environment you can activate some other profile + use another option that spring boot offers for free: --spring.config.locations=.... This one allows specifying an external source of configuration.
So, you don't need to copy resources, fiddle with property source and so forth, instead, you can rely on spring boot regular mechanisms of configurations.
All-in-all you can read the relevant chapter in documentation but this should cover a deployment case.
Last but not least, there are precedences here, so some configuration ways can override the others (I mean if there is a clash between property values with the same name).

How to include external configuration resources to classpath in Spring (Spring Boot)?

I have 3rd party library that is configured by placing properties file on the root of the classpath. That library is using getClass().getResourceAsStream("/file.properties") to load that file. As it is 3rd party, it is unmodifiable. I have placed that configuration file into external resources directory (not to be mistaken with resources from eg. Maven's or Gradle's directory structure.
Directory structure is like this.
How to run/configure Spring boot to include content of resources directory to the classpath so getResourceAsStream wil work?
On SE application I would simply do java -jar myApp.jar with classpath in MANIFEST and that would work.
EDIT:
Just a word of clarification - putting configuration file inside project resources (along sources) is missing the whole point. I want to keep configuration externalized.
Here is how you can do it:
1.- Change your spring-boot-maven-plugin configuration to enable the Spring Boot PropertiesLauncher:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<layout>ZIP</layout>
</configuration>
</plugin>
</plugins>
</build>
2.- Launch your Spring Boot Application setting the location of the external properties file:
java -jar -Dloader.path=PATH_TO_PROPERTIES_FOLDER spring-ms-0.0.1-SNAPSHOT.jar
Assuming this folders:
/home/user/
|--- file.properties
|--- spring-mg-0.0.1-SNAPSHOT.jar
You should launch it like this: java -jar -Dloader.path=/home/user spring-ms-0.0.1-SNAPSHOT.jar

Why is my ${user.home} variable resoled at build time

I have a JHipster generated application with an YAML property file that looks like this:
storage:
location: ${user.home}/my/folder
My problem is that the variable ${user.home} is resolved at build time, when I run mvn package (on Jenkins). So the property is already resolved in the resulting artifact, hence when I deploy on on my server, that path contains the resolved home of the user Jenkins.
Anybody know who is doing this and why? I was expecting that the variable would be resolved at runtime.
Thanks.
Valentin
I'm not totally sure of how JHipster builds on top of Spring Boot, but my guess would be that it's Maven's resource filtering that's expanding ${user.home} at build time. It's enabled by default by spring-boot-starter-parent for application.properties and application.yaml in src/main/resources.
This Spring Boot issue contains some more information, along with details of a configuration change that you may like to make so that ${…} entries are no longer filtered:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.6</version>
<configuration>
<encoding>UTF-8</encoding>
<delimiters>
<delimiter>#</delimiter>
</delimiters>
<useDefaultDelimiters>false</useDefaultDelimiters>
</configuration>
</plugin>

Where should a custom Netbeans Platform conf. file be so that maven finds it?

Applications built on top of the NetBeans platform have a <myappdir>/etc/<myapp>.conf file determining, among other things, application JVM parameters. Historically, this file was a part of the NetBeans IDE installation (as far as I could tell), but starting with NB 6.9, custom files are now supported.
I am having trouble packaging a custom configuration file using Maven to build the application.
I imagine the app.conf property should have been set in the project's pom under project/build/pluginManagement/plugins like so:
<plugin>
...
<configuration>
<brandingToken>${brandingToken}</brandingToken>
<cluster>${brandingToken}</cluster>
<appConf>myapp.conf</appConf>
</configuration>
The maven module representing my application contained no prior source, so I created the src/main/nbm folder and placed myapp.conf in src/main/nbm. This isn't picked up by nbm-maven-plugin. and putting the conf file into src/main/resources doesn't make a difference.
So, can anyone explain how a NetBeans Platform application with a custom configuration file can be built using maven?
UPDATE:
With Tim's prod in the right direction, I found the answer documented on Geertjan's blog. The solution is to configure the nbm-maven-plugin like so in the application module pom:
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>nbm-maven-plugin</artifactId>
<configuration>
<etcConfFile>src/main/resources/my.conf</etcConfFile>
</configuration>
</plugin>
</plugins>
</build>
BTW, if you need a second name with Geertjan, you're not really a NetBeans platform developer. ;)
Have a look at the documentation of the nbm:cluster-app plugin, specifically the part on the conf file.
As per my understanding that should allow you to replace the default one with a custom one that you create.

Resources