Spring Boot Externalized Config on Command Line

Spring Boot applications do not always have to serve as a web service located on the Internet. You can also use Spring Boot (or Spring without the Boot) for a command-line utility. I was recently faced with this task, and one requirement for the tool was to support setting a profile-specific configuration on the command line. This isn’t earth-shattering per se since that is a regular Spring feature. The goal was to provide a profile-specific configuration file on the command line that is not bundled in the application.

Imagine developing a Cloud service and running different environments for the different phases of your project – one for development tests, a staging environment, and, finally, the production environment. Connecting to the different environments may require secrets you do not want to be bundled in the application – and, thus, the source tree.

Now, you could roll your own configuration file reader. But wouldn’t it be nice to make full support of Spring’s @Value annotation or @ConfigurationProperties classes?

Setup

In typical Spring fashion, there are multiple ways to do it. First, a bit of setup, namely the configuration class and the configuration itself. You can find the complete source code on GitHub.

I prefer @ConfigurationProperties classes over @Value, so here we go.

@Data
@NoArgsConstructor
@AllArgsConstructor
@ConfigurationProperties("external-config")
public class ExternalConfigProperties {

    private Location input;
    private Location output;

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Location {
        private String path;
    }
}

The @Configuration class tells Spring Boot to consider using the config-properties class. Nothing special. The critical bit is the @EnableConfigurationProperties(ExternalConfigProperties.class) annotation.

@Configuration
@RequiredArgsConstructor
@EnableConfigurationProperties(ExternalConfigProperties.class)
public class AppConfig {

    private final ExternalConfigProperties externalConfigProperties;

    @Bean
    public AppRunner appRunner() {
        return new AppRunner(externalConfigProperties);
    }
}

And finally, the bundled application.yml configuration file.

logging:
  level:
    root: INFO
    com.thecodeslinger.externalconfig.ExternalConfigApplication: WARN

external-config:
  input:
    path: /home/bundled/thecode
  output:
    path: /home/bundled/slinger

Since it is just a demo, the values are merely dummies. I tried to add a bit of spice by creating a nested structure.

Usage

How would you specify a configuration file on the command line?

Example #1: Use a “config” folder

In the current working directory, create a folder named “config” and add a file named “application.yml” to it. You do not have to specify anything on the command line using this solution. Spring Boot will automatically pick up the additional configuration.

src % ls
config	main

src % ls config 
application.yml

src % java -jar ../target/external-config-1.0.0.jar param1
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.6.2)

-> AppRunner.run() Command Line Arguments
Argument: param1
-> ExternalConfigProperties
Input path: /Users/bundled/thecode
Output path: /Users/bundled/slinger

The “config” folder can be in a completely different location from the executed JAR file. If you require more than one configuration file, e.g., to support multiple profiles, you can typically append the profile name to the application.yml.

src % ls config 
application-mac.yml

src % java -jar ../target/external-config-1.0.0.jar param1 --spring.profiles.active=mac
-> AppRunner.run() Command Line Arguments
Argument: param1
Argument: --spring.profiles.active=mac
-> ExternalConfigProperties
Input path: /Users/mac/thecode
Output path: /Users/mac/slinger

Note the differences in the config:

  • It starts with “/Users” in the “mac” profile, whereas the bundled default is “/home”.
  • The external config disables the Spring banner.

There is a second option for setting the profile configuration: a JVM parameter instead of an application parameter. The Spring option will not appear as a command-line argument for your application when you employ this method.

src % java -Dspring.profiles.active=mac -jar ../target/external-config-1.0.0.jar param1
-> AppRunner.run() Command Line Arguments
Argument: param1
-> ExternalConfigProperties
Input path: /Users/mac/thecode
Output path: /Users/mac/slinger

Notice that you now use “-D” instead of “--” to precede the configuration setting spring.profiles.active=mac.

Example #2: Set a config folder

Instead of relying on an implicit “config” folder in the current working directory, you can set any arbitrarily named folder on the command line.

Important: The folder must end with a “/”.

Spring supports two configuration options to achieve this:

  • spring.config.location
  • spring.config.additional-location

The first option replaces the complete bundled file with a file in the folder you set on the command line. The second option augments the bundled file and only overwrites the bundled values with those found in the folder’s file.

Therefore, the first option must be a complete file that cannot rely on defaults. With the second option, you only set the values you want to change.

The file’s name must follow the same pattern as in Example #1application.yml

 or application-<profile>.yml.

Because Spring is complicated, you can also set either of these options using JVM or application parameters.

Assuming the filename is application.yml and using a JVM parameter:

% java -Dspring.config.additional-location=src/config/ -jar target/external-config-1.0.0.jar param1 param2

-> AppRunner.run() Command Line Arguments
Argument: param1
Argument: param2
-> ExternalConfigProperties
Input path: /Users/mac/thecode
Output path: /Users/mac/slinger

Assuming the filename is application-mac.yml and using application parameters:

% java -jar target/external-config-1.0.0.jar param1 param2 --spring.config.additional-location=src/config/ --spring.profiles.active=mac

-> AppRunner.run() Command Line Arguments
Argument: param1
Argument: param2
Argument: --spring.config.location=src/config/
Argument: --spring.profiles.active=mac
-> ExternalConfigProperties
Input path: /Users/mac/thecode
Output path: /Users/mac/slinger

The same applies to the spring.config.location configuration option.

Example #3: Specify a file explicitly

As before, you can use spring.config.location or spring.config.additional-location, and the same rules regarding replacing and augmenting apply. Only this time, you do not set a folder but a file. A profile is not required anymore.

% java -Dspring.config.location=src/config/application-mac.yml -jar target/external-config-1.0.0.jar param1 param2

Or

% java -jar target/external-config-1.0.0.jar param1 param2 \
       --spring.config.location=src/config/application-mac.yml

Famous Last Words

As you can see, Spring allows for a lot of flexibility, and I have not even shown all possible permutations on how you can combine these options. The most compatible way is to use JVM arguments since the Spring configuration options are not passed to your application’s list of arguments. For a simple demo utility, this is a non-issue. However, if you rely on a 3rd party command line parser, like Apache Commons CLI, or build your own, you might run into issues. The parser of your choice may not recognize the additional parameters and complain or trip during parsing. I plan to tackle this problem with Apache Commons CLI in another blog post, where I noticed this behavior.

Thank you very much for reading.

My Year in Video Gaming 2021

2021 has been a challenging year, for obvious reasons, but also in other personal aspects that are not part of this little essay. Despite all the trials and tribulations, I have probably never played so many games in just one year – some of them in Coop and others all on my lonesome. Many of them I finished, others I, or we, aborted. But not only that, I have also managed to transition from PC gaming to console gaming – a long-held goal of mine.

As always, I am pretty late to the party because I have trouble motivating myself to write stuff, despite having the ideas and mentally developing concepts for them. Much thinking, few doing. One of my 2021 issues.

(I am surprised I managed to get this huge Halo Infinite review out the door.)Here is how this will go. I am starting with a story about why I replaced my gaming PC with consoles and a laptop. Then I transition into my experience with said consoles, and I conclude this gaming year review with the list of games I have played in lonely-mode or Coop. Don’t worry. I didn’t go Halo Infinite on every game. I kept it short-ish because the list is astonishingly long.

Read More »

Halo Infinite Review

When you look back at the history of video-based media, how many games or movies come to your mind with such an iconic theme song that it always evokes a particular feeling whenever you hear it? A theme that you immediately recognize and that conjures specific scenes or gameplay moments you are so fond of? Off the top of my head, I can think of two: The Imperial March from Star Wars and Halo’s invigorating battle soundtrack. Halo is back, infinitely better than Halo 5, and along with it, its recognizable music. I suggest you set the perfect mood and open the link above, and then come back and read my review of Halo Infinite. Start from the beginning because I linked directly to the battle music part (but that is also a good choice).

Now, is it even worth getting in the mood? If you ask yourself, I hope you do not mean my writing 😉. I hope you ask that question because you are anxious for a good game but afraid you might get disappointed. When I read and watched many reviews from known media outlets, I found very different opinions and wasn’t sure what to think. IGN mainly had positive things to say and was very upbeat in their Halo Infinite podcast episode. In contrast, the Germany-based Golem.de website found rather harsh words for some parts, mainly storytelling and the new AI (more on that later). The most common denominator among all of them was the excellent feeling combat. Looking at the complete experience, I think I land somewhere in the middle between Great and Mediocre, and if you are still curious, I will tell you why.

Read More »

Create Native Java Executable using jpackage – Sort of

I have always been the kind of developer who prefers to use native code and write native code. My background is in C++, and I have worked with Microsoft’s WinAPI early in my career. That is to say: I like it fast, and I do not mind going to lower levels.

I am not stuck in the past, though, and as such, I, too, have evolved with the times. I still like C++, but I also see how languages like Java and its great tooling can boost productivity in comparison. As a result, I write code fast. Java is the tool of the trade at my current job, and performance usually is not a problem anymore. The JVM has improved, and computer hardware has, so performance is usually not an issue anymore.

There is one little problem, however: Usage. Let me explain.

Read More »

Apple Silicon M1 for Software Development: Java, C++ with Qt

Apple’s laptops have been making quite the splash since the end of 2020 and have made a massive comeback as a professional tool one year later with the M1 Pro and Max designs. Most of the reviews I have seen focus on the editing and rendering capabilities of these new MacBooks. A few reviewers throw a compile test in the mix, but compiling Chromium or any other huge project is only a part of the equation. Developers don’t just compile code; they also use tools and IDEs to develop their software.

Being new to the M1 world, I wanted to recap my experiences so far briefly. I use Java professionally, and I also have a C++ application based on the Qt framework that I wrote an eon ago and still use productively. Being a former C++ professional, I am about native performance, and I like native software. Therefore, I intended to utilize as many Apple Silicon-native tools as possible. Luckily, one year after its release to the desktop world, the most popular applications have caught up. Let me go through my tool suite one by one.

Read More »

Windows 11 Host VirtualBox Install Error “This app can’t run because it causes security or performance issues”

I have recently upgraded to Windows 11 out of curiosity. Despite the more or less negative first impression, I decided to continue to use it. One of the first applications I install is VirtualBox to try out different Linux flavors and stay current in that world. To my surprise, the VirtualBox installer (version 6.1.26) would not start. Windows was complaining about issues with this software.

> This app can’t run because it causes security or performance issues > on Windows. A new version may be available. Check with your software > provider for an updated version that runs on this version of > Windows.

Well, I checked because it was the latest version of VirtualBox. I found hints on the Internet that VirtualBox does run on Windows 11, albeit without indicating what these persons had done.

A little bit discouraged, I clicked the "Learn more" button. You never know; it might actually be helpful – or a complete waste of time. In this instance, it was of great help. It redirected me to the following Microsoft page discussing the "A driver can’t load on this device issue". It also contains a very convenient link to the corresponding location in the Windows Defender application. Somehow I cannot reproduce that link for your convenience so you must visit Microsoft’s site yourself.

Be aware. There may be a security risk associated with disabling this setting. I have not yet dug deeper to ascertain the whole picture. I figured it must have been disabled or not existed on Windows 10 at all, and I was fine there. Windows will ask you several times to grant administrative rights to perform the operation and require a reboot.

After that, VirtualBox was installed and ran just fine.

Curious, I wondered if I could disable the setting once VirtualBox was installed.

Well, I could not. Windows will try and fail. If you click "Review incompatible drivers", it will show you which component prevents the change. And sure enough, it is VirtualBox.

We will see if Oracle’s VirtualBox team can figure this out, but I would assume so. For now, this works for me.

I hope this has helped you. Thank you for reading.

The Ascent Coop Review Xbox Series X

Do you know the feeling that you occasionally get when watching a gameplay trailer, and you immediately want to get your hands on the game? Like, right now? This sensation does not come around too often for me, and two games managed to do just that last year. One was Outriders and the other one The Ascent, which I am discussing today. I am not sure what exactly did it for me, but probably because it reminded me of something I played in my youth. In 1999, a game named Expendable made the rounds, primarily due to its stunning visuals at the time. Back then, it demonstrated the power of a graphics feature called Environment Mapped Bump Mapping to enamor the game’s textures with depth information and more perceived detail. The core visuals will not excite anyone in 2021, but that game was full of effects and did not hold them back. Expandable still puts on quite a show. 

Games like this are a rare breed and seem to catch my eye whenever one pops up. A more recent example of this type of game that I am aware of is Halo Spartan Assault and Halo Spartan Strike – of which I played the first one. Combine this with stunning visuals in a futuristic, gritty, cyberpunk-themed world, and you get The Ascent. Because it is 2021, no game can make do without some RPG elements. Thus, you get to create your character, level up, and collect loot along the way, making shooting stuff more enjoyable.

And enjoyable it is. Once you get to the point where your brain can cope with the twin-stick-shooting mechanics, and you start to both move and aim in the right direction, The Ascent begins to make a lot of fun – especially in Coop. I discovered how the game works with another player, which is always more motivating than figuring out weird concepts alone. After a while, it started to feel right, and I wanted to continue playing weekend after weekend until we had beaten the game – and that is a good sign.

Here is my report on The Ascent in Coop mode: the good, the bad, and the ugly.

Read More »

Windows 11 First Look at New Visual Design – Not Yet a Fan

Thanks to a recent article by Paul Thurrott, I finally convinced myself to give Windows 11 a try. I was hesitant at first because of all the negative information regarding some of Microsoft’s choices – and I do not mean Secure Boot and TPM. I was not sure if I wanted to support this behavior. Be that as it may, maybe a topic for another day, what finally convinced me was the fact that Secure Boot must not even be enabled. It is enough that the system supports it. This means I can still run a Linux installation in parallel, which I did not want to give up easily.

You must understand that these are really only first impressions. I have not spent hours upon hours with Windows 11 and dug deep into the system. It boils down to an opinion on the visual presentation, the most glaring change compared to Windows 10. Teaser: I do have some mixed feelings about it.

Read More »

Fedora Linux 35 Beta Install NVIDIA Driver

This is a quick one because the installation works in the same way as it did in Fedora 34.

First, I added the RPM Fusion repositories as described here.

sudo dnf install \
  https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm
sudo dnf install \
  https://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm

Next, I installed the akmod-nvidia package like it is explained on this page.

sudo dnf update
sudo dnf install akmod-nvidia

One reboot later, the NVIDIA module was up and running.

$ lsmod | grep nvidia
nvidia_drm             69632  4
nvidia_modeset       1200128  8 nvidia_drm
nvidia              35332096  408 nvidia_modeset
drm_kms_helper        303104  1 nvidia_drm
drm                   630784  8 drm_kms_helper,nvidia,nvidia_drm

For completeness: my computer has an NVIDIA GT1030.

I hope this helped you, and thank you for reading.

C# Delegate, Action, Func, Predicate Explained

Depending on your entry point to delegates, the documentation might look a tad confusing at first. For me, it was The delegate type section of the C# language reference. It throws around terms like Action, Func, Events, custom delegate types. Predicate is also related to this topic, and this was what I was looking for.

Let me briefly explain what all those words mean and how they relate to delegate. Then I will explain why I was looking into this.

Short teaser: “Named Predicate”, like a Hibernate Named Query.

Read More »

Emulate Java Enums With Values in C# (Pt. 2, Improved With Conversion Operator Overload)

In a previous blog post, I demonstrated how Java’ enums that contain one or more values/objects can be emulated with C#. One thing bothered me, though: the switch statement and how inconvenient it was to determine the proper type. Worst of all, it was not type-safe. In my simple example, it was easy because I was using strings. Imagine your fake-enum does not contain a string to quickly identify the instance.

Well, there is a prettier workaround – and it involves an actual enum. I was thinking about how the same could be done in C++ and in C++, you can have type conversion operators. Then I searched if such a feature also exists in C#, and sure enough, it does.

Read More »

Emulate Java Enums With Values in C#

Update August 28, 2021

I have written a follow-up that improves on the following solution using a type conversion operator overload.

When I started dabbling in C#, I wondered if it supports values in enums. In Java, an enum instance can have properties (called fields in Java lingo) associated with the enum’s literals. By taking advantage of this feature, you can encode more information in an enum, like a string, for example, or a constant number. You can even embed instantiated class objects, maybe to associate an object factory with a literal.

In my use case, I wanted to achieve a form of a key-value-pair mapping. I require certain illegal characters in the NTFS file or directory names to be replaced with a given code. I use HTML encoding for my needs because I can simply look up the values online if I need to.

Here is the Java reference example. First, let me start with the basic enum definition (I use Lombok to auto-generate boilerplate code like the constructor and accessors).

@Getter
@RequiredArgsConstructor
enum CharacterReplacementCode  {
    COLON(":", "&58;"),
    POUND("#", "&35;"),
    QUESTION_MARK("?", "&63;"); 

    private final String character;
    private final String replacement;
    
    @Override
    public String toString() {
        return String.format("Character '%s' substituted by code '%s'", character, replacement); 
    }
}
Read More »

KDE Plasma Remap Meta/Windows Key From App Launcher to KRunner

Sometimes I want to run applications that I do not have pinned to the quick-launch bar of my choice’s operating system/desktop environment. To do that, I am used to pressing the Windows/Meta Key, begin typing a few characters, and hit Enter. This is muscle memory and hard to get rid of. Although it does not matter which UI opens, I do not need the full-blown KDE Application Launcher, Gnome Shell, or Windows Start Menu. The amount of UI that pops up and changes while searching for the app is distracting.

Therefore, I wondered whether I could remap the Meta/Windows key from opening the Application Launcher to opening KRunner. And you can, but only on the command line.

Remove the key mapping from the Application Launcher.

kwriteconfig5 --file kwinrc --group ModifierOnlyShortcuts --key Meta ""

Open KRunner instead.

kwriteconfig5 --file kwinrc --group ModifierOnlyShortcuts --key Meta "org.kde.krunner,/App,,toggleDisplay"

Apply the changes to the current session.

qdbus org.kde.KWin /KWin reconfigure

I hope this helps you. Thank you for reading.

Right to Repair: Do Not Forget Firmware

Early July 2021, US president Joe Biden signed an executive order strengthening the right to repair in America. It is all the rage in the YouTuber space. Over here in Europe, the European Parliament is also working on encouraging reuse and repair to save on resources (Ecodesign Requirements, Grant EU Consumers Right to Repair, Europe Reduce Waste by Guaranteeing Right to Repair). However, I do not think the movement is as strong as in the US, based on my perception of the media coverage. I had to actively search for information rather than having it thrown at me by media outlets, old-school and modern alike.

Disclaimer: This might just be my way of looking for and consuming information. I strongly prefer non-German modern tech media (read YouTube creators) because I am yet to find one that produces at the same level of production quality as someone like Linus Media Group, as one example. I watch German news, though, so I am not entirely ignoring my own country 😉

Now, the topic of this post is not where I get my information or how far the current state of legislation has come everywhere in the world.

I know that "Right to Repair" goes way beyond smartphones and computers. My focus is on consumer technology because that is where my interests are.

I want to talk about the software that runs on the hardware since it is just as important to a product’s lifetime. Washing machines and similar household appliances are becoming "smarter and smarter" with every new generation, so it is no longer just phones and tablets. Together with mobile computers, the latter two categories are likely what everybody interested in tech immediately thinks about when hearing "Right to Repair".

Read More »

Terraform Azure Error SoftDeletedVaultDoesNotExist

I just ran into a frustrating error that seemed unexplainable to me. My goal was to replace an existing Azure Resource Group with a new one managed entirely with Terraform. Besides a few other errors, this SoftDeletedVaultDoesNotExist was incredibly confusing because no more Key Vaults were found in the Resource Group’s list of resources.

Error: creating Vault: (Name "my-fancy-key-vault" / Resource Group "The-Codeslinger"): 
keyvault.VaultsClient#CreateOrUpdate: Failure sending request: StatusCode=0 -- 
Original Error: Code="SoftDeletedVaultDoesNotExist" 
Message="A soft deleted vault with the given name does not exist. 
Ensure that the name for the vault that is being attempted to recover is in a recoverable state. 
For more information on soft delete please follow this link https://go.microsoft.com/fwlink/?linkid=2149745"

with module.base.azurerm_key_vault.keyvault,
on terraform\key_vault.tf line 9, in resource "azurerm_key_vault" "keyvault":
    9: resource "azurerm_key_vault" "keyvault" {

That is because it was soft-delete enabled. And it was the Key Vault from the other Resource Group that I previously cleared of all resources, not the new Resource Group.

Using the az CLI you can display it, though.

> az keyvault list-deleted
[
    {
        "id": "/subscriptions/<subscription-id>/providers/Microsoft.KeyVault/locations/westeurope/deletedVaults/my-fancy-key-vault",
        "name": "my-fancy-key-vault",
        "properties": {
            "deletionDate": "2021-08-02T09:39:29+00:00",
            "location": "westeurope",
            "purgeProtectionEnabled": null,
            "scheduledPurgeDate": "2021-10-31T09:39:29+00:00",
            "tags": {
                "customer": "The-Codeslinger",
                "source": "Terraform"
            },
            "vaultId": "/subscriptions/<subscription-id>/resourceGroups/My-Other-ResourceGroup/providers/Microsoft.KeyVault/vaults/my-fancy-key-vault"
        },
        "type": "Microsoft.KeyVault/deletedVaults"
    }
]

And finally delete it.

> az keyvault purge --name my-fancy-key-vault

After that, it is gone.

$ az keyvault list-deleted
[]

Another option seems to be the Azure Portal, but I discovered this only after removing it on the command line.