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 »

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.

Qt6 QtCreator Crash After Install on Ubuntu 21.04

Hopping Linux distributions, I came to Ubuntu 21.04, and one of the first things I do is install Qt manually. I have described the process in a previous blog post on Linux Mint, and it is the same for Ubuntu. Except for a tiny detail. On Ubuntu, the bundled QtCreator immediately crashes and triggers a "Send Diagnostic" dialog.

$ /opt/Qt/Tools/QtCreator/bin/qtcreator
qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was 
found. This application failed to start because no Qt platform plugin could be 
initialized. Reinstalling the application may fix this problem.

Available platform plugins are: eglfs, linuxfb, minimal, minimalegl, offscreen, vnc, 
xcb.

The fix is simple.

sudo apt install libxcb-xinerama0

I hope this helps. Thank you for reading.

Sign and Verify JWT With Hashicorp Vault REST API

Cryptography is complicated in more than just one way. Therefore, it is commonly recommended not to roll your own, but instead, employ tried and tested methods. Unless you are an experienced cryptographer, it is likely to overlook crucial things, for example, when to authenticate an encrypted message – before decrypting or after? This blog post is about JSON Web Tokens that are digitally signed with an RSA key. Instead of implementing the signing and verification code yourself, you should be using a dedicated server component to do the complex crypto for you, like Hashicorp Vault.

Read More »

Write ID3 mp3 Tags, Cover Art with Python and eyed3

In March 2019, I wrote about using Python with the "pytaglib" library to read and modify audio files’ metadata. This solution worked nicely for what I needed at the time, but as I rewrote my WAV-to-MP3 conversion in Python, I found that it lacked support for adding cover art to the files. After a bit of research, I found eyed3. It also comes with a nice side-effect: it does not require installation of the Taglib C++ library.

Installation is simple.

pip install eyeD3

Additionally, on Windows, you need this, too:

pip install python-magic-bin

For more details, visit the installation guide. Like my old pytaglib post, I will keep this one short and only show code samples for the most relevant tasks.

Before you do anything, import the eyed3 library, of course.

import eyed3

Load a file.

song = eyed3.load(file)

If the file does not yet have any tags, you must create them before setting any metadata.

if not song.tag:
    song.initTag()

Note that this erases existing tags, so only call that if you start from scratch. Now you are ready to set the individual tags or read them if you need them.

song.tag.artist = "Behemoth"
song.tag.album = "The Satanist"
song.tag.genre = "Black Metal"
song.tag.recording_date = 2014
song.tag.track_num = 4
song.tag.title = "Ora pro nobis Lucifer"

The important piece for me, write cover art.

with open(cover_art_filename, "rb") as cover_art:
    song.tag.images.set(3, cover_art.read(), "image/jpeg")

The value 3 indicates that the front cover shall be set. See the documentation for other values. If you are an iTunes user, then select 0 for "Other". iTunes does not seem to like "Front Cover" 🙄.

You may run into a warning message like the following if you use genre names not defined in the ID3 specification.

eyed3.id3:WARNING: Non standard genre name

You do not need to worry about that. If it annoys you, add the following line to your code. eyed3 still writes the tag without any issue.

eyed3.log.setLevel("ERROR")

Convert Java POJO With Protobuf field to JSON Using Jackson

In this blog post, I will explain how to convert a regular Java class that contains a Protobuf message field to JSON using the Jackson library, for example, in a Spring Boot application as a return value of an @Controller method.

You might wonder, how this is such a big deal? After all, you can create complex POJO hierarchies, and Jackson will pick them up just fine. Well, maybe this error message will convince you.

o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [
    Request processing failed; nested exception is org.springframework.http.converter.HttpMessageConversionException: 
    Type definition error: [simple type, class com.google.protobuf.UnknownFieldSet]; 
    nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Direct self-reference leading to cycle 
    (through reference chain: com.thecodeslinger.ppjs.web.dto.AwesomeDto["awesomePowerUp"]
        ->com.thecodeslinger.ppjs.proto.AwesomePowerUpOuterClass$AwesomePowerUp["unknownFields"]
        ->com.google.protobuf.UnknownFieldSet["defaultInstanceForType"])] with root cause

Java classes that you create with the Protobuf compiler require their JSON converter JsonFormat.Printer. So, how can we get Jackson and JsonFormat.Printer love each other and have a wedding together?

Simple: we create a custom JsonSerializer.

public class ProtobufSerializer extends JsonSerializer<Message> {

    private final JsonFormat.Printer protobufJsonPrinter = JsonFormat.printer();

    @Override
    public void serialize(Message anyProtobufMessage, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
            throws IOException {
        // The magic sauce: use the Protobuf JSON converter to write a raw JSON
        // string of the Protobuf message instance.
        jsonGenerator.writeRawValue(protobufJsonPrinter.print(anyProtobufMessage));
    }
}

This class is very simple and can work with any Protobuf Message class instance. This way, it is universal and only needs to be written once. The main ingredient is the jsonGenerator.writeRawValue method that takes the input without modification. Since we already ensure a proper JSON format using Protobuf’s converter, this is no problem in this case. Otherwise, be careful with this method.

The last step is to annotate the Message field in the POJO, so Jackson knows what to do.

@JsonSerialize(using = ProtobufSerializer.class)
private final AwesomePowerUpOuterClass.AwesomePowerUp awesomePowerUp;

You can find a complete working example that uses Spring Boot and a REST endpoint on my Github account.

Install Minikube in VirtualBox on Remote Machine for Kubectl

At work, we are using Kubernetes as a way to run our application services. To test and debug deployments before they go into code review and to the development environment, a local Kubernetes is beneficial. That is where Minikube comes into play. Unfortunately for me, our application services require more resources than my work laptop can provide, especially RAM. Either I close all applications and run Minikube, or I have a helpful browser and IDE window open 😉.

Since I need the local K8s cluster from time to time, I wondered if I could run it on my personal computer and access it from my laptop. This way, I can dedicate at least six physical cores and 24 GB of RAM to the VM (even more, but that was a nice number and more than enough).

Read More »

CMake C++ Custom Library on Windows “Undefined Reference” – No Error on Linux

Here is the short version with a quick setup of the situation and the fix. After that, I’ll elaborate a bit.

TL;DR

Setup

I have a custom C++ library and a separate project for tests (all based on Qt 6). The test project requires the library for execution.

Here is a short excerpt of the CMake scripts, first the library, then the tests.

project(wt2-shared VERSION 2.0.0 DESCRIPTION "WorkTracker2 Shared 
Library")

# To export symbols.
add_compile_definitions(WT2_LIBRARY)

# Snip header + source definitions

add_library(${PROJECT_NAME} ${SOURCES} ${HEADERS})

target_include_directories(${PROJECT_NAME} PUBLIC include/)
target_link_libraries(wt2-shared Qt6::Core Qt6::Sql)
project(wt2-shared-test VERSION 2.0.0 DESCRIPTION "WorkTracker2 
Shared Library Tests")

# Snip header + source definitions

add_executable(${PROJECT_NAME} ${SOURCES} ${HEADERS})

target_include_directories(${PROJECT_NAME} PRIVATE ${INCLUDES})
target_link_libraries(${PROJECT_NAME} Qt6::Core Qt6::Test wt2-shared)

Error

This error only occurred on Windows, and it does not matter which toolchain I used, be it MinGW or MSVC. The result was always the same.

The following shows the MinGW error.

[100%] Linking CXX executable wt2-shared-test.exe    
CMakeFiles\wt2-shared-test.dir/objects.a(testdatasource.cpp.obj):testdatasource.cpp:(.text+0x3e5): 
    undefined reference to `__imp__ZN4Data3Sql13SqlDataSourceC1E7QString'
CMakeFiles\wt2-shared-test.dir/objects.a(testdatasource.cpp.obj):testdatasource.cpp:(.text+0x401): 
    undefined reference to `__imp__ZN4Data3Sql13SqlDataSource4loadEv'
CMakeFiles\wt2-shared-test.dir/objects.a(testdatasource.cpp.obj):testdatasource.cpp:(.text+0x514): 
    undefined reference to `__imp__ZN4Data3Sql13SqlDataSourceC1E7QString'	
CMakeFiles\wt2-shared-test.dir/objects.a(testdatasource.cpp.obj):testdatasource.cpp:(.text+0x530): 
    undefined reference to `__imp__ZN4Data3Sql13SqlDataSource4loadEv'
collect2.exe: error: ld returned 1 exit status
mingw32-make[2]: *** 
[wt2-shared-test\CMakeFiles\wt2-shared-test.dir\build.make:142: 
wt2-shared-test/wt2-shared-test.exe] Error 1

Solution

The add_library definition in the CMakeLists.txt was incomplete.
To make it work, I added SHARED because I want a shared library.

add_library(${PROJECT_NAME} SHARED ${SOURCES} ${HEADERS})

Continue reading, though, to get the full picture. There is more to it than just making the library a shared one.

Read More »

CMake CLI Parameter “generator-name” Usage

This topic shouldn’t even require a blog post, but I find the CMake CLI usage rather odd when it comes to specifying a generator. Here’s a shortened "-h" output.

> cmake -h
Usage

cmake [options] <path-to-source>
cmake [options] <path-to-existing-build>
cmake [options] -S <path-to-source> -B <path-to-build>

Specify a source directory to (re-)generate a build system for it in the
current working directory.  Specify an existing build directory to
re-generate its build system.

Options
-S <path-to-source>          = Explicitly specify a source directory.
-B <path-to-build>           = Explicitly specify a build directory.
-C <initial-cache>           = Pre-load a script to populate the cache.
-D <var>[:<type>]=<value>    = Create or update a cmake cache entry.
-U <globbing_expr>           = Remove matching entries from CMake cache.
-G <generator-name>          = Specify a build system generator.
-T <toolset-name>            = Specify toolset name if supported by
                                generator.
-A <platform-name>           = Specify platform name if supported by
                                generator.

    ...snip...

Generators

The following generators are available on this platform (* marks default):
Visual Studio 16 2019        = Generates Visual Studio 2019 project files.
                                Use -A option to specify architecture.
Visual Studio 15 2017 [arch] = Generates Visual Studio 2017 project files.
                                Optional [arch] can be "Win64" or "ARM".

    ...snip...

Borland Makefiles            = Generates Borland makefiles.
* NMake Makefiles              = Generates NMake makefiles.
NMake Makefiles JOM          = Generates JOM makefiles.
MSYS Makefiles               = Generates MSYS makefiles.
MinGW Makefiles              = Generates a make file for use with
                                mingw32-make.
Unix Makefiles               = Generates standard UNIX makefiles.

    ...snip...
    
Kate - Ninja                 = Generates Kate project files.
Kate - Unix Makefiles        = Generates Kate project files.
Eclipse CDT4 - NMake Makefiles
                            = Generates Eclipse CDT 4.0 project files.
Eclipse CDT4 - MinGW Makefiles
                            = Generates Eclipse CDT 4.0 project files.
Eclipse CDT4 - Ninja         = Generates Eclipse CDT 4.0 project files.
Eclipse CDT4 - Unix Makefiles= Generates Eclipse CDT 4.0 project files.

These generator options do not look like valid parameter values to the "-G" option. But they are. So, if you want to compile on Windows using MinGW, you have to use this.

> cmake -S ../src -B ./ -G "MinGW Makefiles"

Or, if you prefer Visual Studio project files:

> cmake -S ../ -B ./ -G "Visual Studio 15 2017 Win64"

This "syntax" looks weird, and it tripped me for about 10 minutes until I found a sample and understood how it works.

Terraform Azure Error: parsing json result from the Azure CLI: Error waiting for the Azure CLI: exit status 1; Failed to load token files

There are some instances where I have managed to screw up my Azure CLI configuration file with Terraform. It must have something to do with parallel usage of Terraform or Terraform simultaneously with the az tool. Either way, I ran into the following error.

$ terraform refresh
Acquiring state lock. This may take a few moments...

Error: Error building account: Error getting authenticated object ID: Error parsing json result from the Azure CLI: Error aiting for the Azure CLI: exit status 1

  on main.tf line 16, in provider "azurerm":
  16: provider "azurerm" {

I wondered: "What might block the Azure access? Am I maybe not logged in?" So, I went ahead and tried to log in.

$ az login
Failed to load token files. If you have a repro, please log an issue
at https://github.com/Azure/azure-cli/issues. At the same time, you 
can clean up by running 'az account clear' and then 'az login'. 

(Inner Error: Failed to parse /home/rlo/.azure/accessTokens.json with exception: Extra data: line 1 column 18614 (char 18613))

The error probably comes from parallel access to my Azure CLI configuration file. When I opened the /home/rlo/.azure/accessTokens.json, I found some dangling garbage at the end of it that broke the JSON format.

Here’s a snippet of the last few lines.

        "refreshToken": "0.A...",
        "oid": "<oid>",
        "userId": "<userId>",
        "isMRRT": true,
        "_clientId": "<clientId>",
        "_authority": "https://login.microsoftonline.com/<uid>"
    }
]bc1"}]

I took out the trash bc1"}], saved the file, and it worked again. Many access to resources. Such joy 😉

Qt5 QtCreator Error on Linux: stddef.h: No such file or directory – Code model could not parse an included file

The following is an error that has shown itself every time I have installed the Qt5 framework and the QtCreator development environment on a Linux based machine. It never mattered which flavor of Linux; QtCreator always showed this error.

Warning: The code model could not parse an included file, which might lead to incorrect code completion and highlighting, for example. 

fatal error: 'stddef.h' file not found 
note: in file included from /home/rlo/Code/C++/WorkTracker2/WorkTracker2Shared/src/data/taskrepository.h:1: 
note: in file included from /home/rlo/Code/C++/WorkTracker2/WorkTracker2Shared/src/data/taskrepository.h:3: 
note: in file included from /usr/include/c++/9/optional:38: 
note: in file included from /usr/include/c++/9/stdexcept:38: 
note: in file included from /usr/include/c++/9/exception:143: 
note: in file included from /usr/include/c++/9/bits/exception_ptr.h:38: 

Although that message never caused any issues compiling the code, I found it rather annoying, and at some point, annoying enough to search for a solution.

As it turns out, this message appears when you have Clang libraries installed. QtCreator detects that and automatically uses Clang to parse the source code and provide inline error messages and code completion.

You can get rid of this error when you explicitly add the STL header files’ include-path to your project. In my case, I have added the following to my *.pro file.

unix {
    INCLUDEPATH += /usr/lib/gcc/x86_64-linux-gnu/9/include
}

Azure PostgreSQL Error: PSQLException The connection attempt failed

A few days ago at work, I was investigating a strange issue where one of our services could not connect to the Azure Managed PostgreSQL Database from the Kubernetes cluster. Oddly enough, other services of that cluster did not exhibit this behavior.

org.postgresql.util.PSQLException: The connection attempt failed.
        at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:315) ~[postgresql-42.2.16.jar!/:42.2.16]
        at org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:51) ~[postgresql-42.2.16.jar!/:42.2.16]
        at org.postgresql.jdbc.PgConnection.<init>(PgConnection.java:225) ~[postgresql-42.2.16.jar!/:42.2.16]
        at org.postgresql.Driver.makeConnection(Driver.java:465) ~[postgresql-42.2.16.jar!/:42.2.16]
        at org.postgresql.Driver.connect(Driver.java:264) ~[postgresql-42.2.16.jar!/:42.2.16]
        ...
        at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) ~[ehg-hermes.jar:0.13.0-SNAPSHOT]
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:107) ~[ehg-hermes.jar:0.13.0-SNAPSHOT]
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) ~[ehg-hermes.jar:0.13.0-SNAPSHOT]
        at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88) ~[ehg-hermes.jar:0.13.0-SNAPSHOT]
Caused by: java.io.EOFException: null
        at org.postgresql.core.PGStream.receiveChar(PGStream.java:443) ~[postgresql-42.2.16.jar!/:42.2.16]
        at org.postgresql.core.v3.ConnectionFactoryImpl.enableGSSEncrypted(ConnectionFactoryImpl.java:436) ~[postgresql-42.2.16.jar!/:42.2.16]
        at org.postgresql.core.v3.ConnectionFactoryImpl.tryConnect(ConnectionFactoryImpl.java:144) ~[postgresql-42.2.16.jar!/:42.2.16]
        at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:213) ~[postgresql-42.2.16.jar!/:42.2.16]
        ... 46 common frames omitted

As it turns out, it was an issue with the PSQL JDBC driver version that comes bundled with Spring Boot version 2.3.4-RELEASE. All the other services were still built with a slightly older release and therefore used an older PSQL JDBC driver.

The key indicator of what is going on is this method call.

org.postgresql.core.v3.ConnectionFactoryImpl.enableGSSEncrypted

A bit of research led me to a question on StackOverflow that pointed me in the right direction, and ultimately I ended up on Microsoft’s Azure documentation. If you scroll down, you will find a section named "GSS error".

The solution to this problem is simple. If you do not want or cannot change the Spring Boot or PSQL JDBC driver version, e.g., because of automated CVE scans that break builds (the reason we upgraded this one service), then you can solve it with a configuration change. Append gssEncMode=disable to the JDBC connection string.

Example: jdbc:postgresql://svc-pdb-name.postgres.database.azure.com:5432/databasename?gssEncMode=disable