'Primitive Axon App run as Fat JAR Doesn't Autoconfigure Axon Beans

PROBLEM:

RESEARCH: At https://gitlab.com/ZonZonZon/simple-axon.git I've made up a simple Axon-app to show that JAR-artifact built with Gradle-plugin com.github.johnrengelman.shadow doesn't autoconfigure Axon beans when (when run as JAR). Though it runs fine under Intellij.

From project root in terminal:

run gradle clean build shadowJar;
java -jar build/simpleaxon.jar;

Stacktrace is enclosed here. I expect that Axon Autocongiguration provides beans like CommandBus, Snapshotter and other by default.

QUESTION: How to autoconfigure default axon beans in a fat jar?



Solution 1:[1]

So, this took my some investigation to get a hunch what is going wrong, but I know what the problem is. Quick notice, it's not an Axon specific thing, rather the plugin you are using.

I ran your sample project and indeed ended up with the same result; no Axon beans were being wired, ever. That led me to investigate the process of creating fat JAR's step by step. First Maven, then Spring Boot with Maven, then Gradle with Spring Boot and finally with the Shadow plugin you are referring too.

This endeavour landed me on this issue, which states as much as "projects which require the use of META-INF files need to add this to the shadow plugin, and this should be documented".

The portion referenced through this is the following:

import com.github.jengelman.gradle.plugins.shadow.transformers.PropertiesFileTransformer

// Left out all other specifics from your 'build.gradle' file

shadowJar {
    // Required for Spring
    mergeServiceFiles()
    append 'META-INF/spring.handlers'
    append 'META-INF/spring.schemas'
    append 'META-INF/spring.tooling'
    transform(PropertiesFileTransformer) {
        paths = ['META-INF/spring.factories' ]
        mergeStrategy = "append"
    }

    setArchiveFileName("simpleaxon.jar")
    getDestinationDirectory().set(new File(projectDir, "./build"))
}

After adding that piece of logic to your build.gradle file, I could run your sample project as expected.

Solution 2:[2]

I've hit a similar issue when using Axon in a multimodule Gradle project. The app would not work when packaged and worked fine in IDE. The exact error I was getting was

org.axonframework.messaging.annotation.UnsupportedHandlerException: Unable to resolve parameter 0 in handler

The reason for this was because ParameterResolverFactories were not loaded due to the META-INF/services resources not being resolved correctly in the shadow jar plugin as @Steven hinted.

I've managed to fix it with simply (using Kotlin DSL in Gradle):

tasks.shadowJar {
  mergeServiceFiles()
}

Solution 3:[3]

@Steven 's solution was the only one working for me, after searching for a long time for other solutions.

The Gradle Kotlin Version looks like this https://github.com/spring-projects/spring-boot/issues/1828#issuecomment-607352468:

import com.github.jengelman.gradle.plugins.shadow.transformers.PropertiesFileTransformer
plugins {
    id("com.github.johnrengelman.shadow") version "7.1.2"
}
...
tasks.shadowJar {
    // Required for Spring.
    // The shadowJar plugin should merge the services correctly, but it doesn't!
    mergeServiceFiles()
    append("META-INF/spring.handlers")
    append("META-INF/spring.schemas")
    append("META-INF/spring.tooling")
    transform(
        PropertiesFileTransformer().apply {
            paths = mutableListOf("META-INF/spring.factories")
            mergeStrategy = "append"
        })
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Steven
Solution 2
Solution 3 Jan