jaxb2-maven-plugin 2.4 and Java 10

Well, based on my own experience and based on discussion here I claim that:

Maven plugin “jaxb2-maven-plugin” in version 2.4 is not ready for Java 10.

Java version:

$ java -version
java version "10.0.1" 2018-04-17
Java(TM) SE Runtime Environment 18.3 (build 10.0.1+10)
Java HotSpot(TM) 64-Bit Server VM 18.3 (build 10.0.1+10, mixed mode)

Maven version:

$ mvn -v
Apache Maven 3.5.2
Maven home: /usr/share/maven
Java version: 10.0.1, vendor: Oracle Corporation
...

Error reported by Maven:

[ERROR] Failed to execute goal org.codehaus.mojo:jaxb2-maven-plugin:2.4:xjc (xjc) on project ...: Execution xjc of goal org.codehaus.mojo:jaxb2-maven-plugin:2.4:xjc failed: A required class was missing while executing org.codehaus.mojo:jaxb2-maven-plugin:2.4:xjc: javax/activation/DataSource
[ERROR] -----------------------------------------------------
[ERROR] realm =    plugin>org.codehaus.mojo:jaxb2-maven-plugin:2.4
[ERROR] strategy = org.codehaus.plexus.classworlds.strategy.SelfFirstStrategy
[ERROR] urls[0] = file:/home/.../.m2/repository/org/codehaus/mojo/jaxb2-maven-plugin/2.4/jaxb2-maven-plugin-2.4.jar
[ERROR] urls[1] = file:/home/.../.m2/repository/javax/xml/bind/jaxb-api/2.3.0/jaxb-api-2.3.0.jar
[ERROR] urls[2] = file:/home/.../.m2/repository/org/glassfish/jaxb/jaxb-core/2.3.0/jaxb-core-2.3.0.jar
[ERROR] urls[3] = file:/home/.../.m2/repository/org/glassfish/jaxb/txw2/2.3.0/txw2-2.3.0.jar
[ERROR] urls[4] = file:/home/.../.m2/repository/org/glassfish/jaxb/jaxb-runtime/2.3.0/jaxb-runtime-2.3.0.jar
[ERROR] urls[5] = file:/home/.../.m2/repository/org/jvnet/staxex/stax-ex/1.7.8/stax-ex-1.7.8.jar
[ERROR] urls[6] = file:/home/.../.m2/repository/com/sun/xml/fastinfoset/FastInfoset/1.2.13/FastInfoset-1.2.13.jar
[ERROR] urls[7] = file:/home/.../.m2/repository/org/glassfish/jaxb/jaxb-xjc/2.3.0/jaxb-xjc-2.3.0.jar
[ERROR] urls[8] = file:/home/.../.m2/repository/org/glassfish/jaxb/xsom/2.3.0/xsom-2.3.0.jar
[ERROR] urls[9] = file:/home/.../.m2/repository/org/glassfish/jaxb/codemodel/2.3.0/codemodel-2.3.0.jar
[ERROR] urls[10] = file:/home/.../.m2/repository/com/sun/xml/bind/external/rngom/2.3.0/rngom-2.3.0.jar
[ERROR] urls[11] = file:/home/.../.m2/repository/com/sun/xml/dtd-parser/dtd-parser/1.2/dtd-parser-1.2.jar
[ERROR] urls[12] = file:/home/.../.m2/repository/com/sun/istack/istack-commons-tools/3.0.5/istack-commons-tools-3.0.5.jar
[ERROR] urls[13] = file:/home/.../.m2/repository/org/apache/ant/ant/1.7.0/ant-1.7.0.jar
[ERROR] urls[14] = file:/home/.../.m2/repository/org/apache/ant/ant-launcher/1.7.0/ant-launcher-1.7.0.jar
[ERROR] urls[15] = file:/home/.../.m2/repository/relaxngDatatype/relaxngDatatype/20020414/relaxngDatatype-20020414.jar
[ERROR] urls[16] = file:/home/.../.m2/repository/org/glassfish/jaxb/jaxb-jxc/2.3.0/jaxb-jxc-2.3.0.jar
[ERROR] urls[17] = file:/home/.../.m2/repository/com/thoughtworks/qdox/qdox/2.0-M8/qdox-2.0-M8.jar
[ERROR] urls[18] = file:/home/.../.m2/repository/org/sonatype/sisu/sisu-inject-bean/2.3.0/sisu-inject-bean-2.3.0.jar
[ERROR] urls[19] = file:/home/.../.m2/repository/org/sonatype/sisu/sisu-guice/3.1.0/sisu-guice-3.1.0-no_aop.jar
[ERROR] urls[20] = file:/home/.../.m2/repository/org/sonatype/sisu/sisu-guava/0.9.9/sisu-guava-0.9.9.jar
[ERROR] urls[21] = file:/home/.../.m2/repository/org/sonatype/aether/aether-util/1.13.1/aether-util-1.13.1.jar
[ERROR] urls[22] = file:/home/.../.m2/repository/org/codehaus/plexus/plexus-interpolation/1.14/plexus-interpolation-1.14.jar
[ERROR] urls[23] = file:/home/.../.m2/repository/org/codehaus/plexus/plexus-component-annotations/1.5.5/plexus-component-annotations-1.5.5.jar
[ERROR] urls[24] = file:/home/.../.m2/repository/org/sonatype/plexus/plexus-sec-dispatcher/1.3/plexus-sec-dispatcher-1.3.jar
[ERROR] urls[25] = file:/home/.../.m2/repository/org/sonatype/plexus/plexus-cipher/1.4/plexus-cipher-1.4.jar
[ERROR] urls[26] = file:/home/.../.m2/repository/org/apache/maven/plugin-tools/maven-plugin-annotations/3.5.1/maven-plugin-annotations-3.5.1.jar
[ERROR] urls[27] = file:/home/.../.m2/repository/org/apache/maven/skins/maven-fluido-skin/1.6/maven-fluido-skin-1.6.jar
[ERROR] urls[28] = file:/home/.../.m2/repository/org/codehaus/plexus/plexus-compiler-api/2.5/plexus-compiler-api-2.5.jar
[ERROR] urls[29] = file:/home/.../.m2/repository/org/codehaus/plexus/plexus-utils/3.1.0/plexus-utils-3.1.0.jar
[ERROR] urls[30] = file:/home/.../.m2/repository/org/sonatype/plexus/plexus-build-api/0.0.7/plexus-build-api-0.0.7.jar
[ERROR] urls[31] = file:/home/.../.m2/repository/com/sun/istack/istack-commons-runtime/3.0.5/istack-commons-runtime-3.0.5.jar
[ERROR] Number of foreign imports: 1
[ERROR] import: Entry[import  from realm ClassRealm[maven.api, parent: null]]
[ERROR] 
[ERROR] -----------------------------------------------------
[ERROR] : javax.activation.DataSource

Relevant parts of pom.xml to reproduce:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>...</groupId>
	<artifactId>...</artifactId>
	<version>...</version>
	<packaging>jar</packaging>
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<maven.compiler.source>10</maven.compiler.source>
		<maven.compiler.target>10</maven.compiler.target>
	</properties>
	<!-- ... -->
	<build>
		<plugins>
			<plugin>
				<groupId>org.codehaus.mojo</groupId>
				<artifactId>jaxb2-maven-plugin</artifactId>
				<version>2.4</version>
				<executions>
					<execution>
						<id>xjc</id>
						<goals>
							<goal>xjc</goal>
						</goals>
					</execution>
				</executions>
				<configuration>
					<packageName>some.package</packageName>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

NOTE: The bad news is that none of older versions of jaxb2-maven-plugin worked with Java 10 as well.

Solution

The solution is to use exec-maven-plugin to invoke xjc directly. The version of this plugin that worked for me with Java 10 was 1.5.0 – so not the latest one at the time of writing this article (1.6.0).

But we need 2 more Maven plugins: maven-antrun-plugin and build-helper-maven-plugin.

The maven-antrun-plugin is there to create folders on path {project directory}/target/generated-sources as xjc rejects to create missing directories itself.

The build-helper-maven-plugin just adds the folder {project directory}/target/generated-sources to set of Java sources compiled by Maven.

Relevant parts of pom.xml to make it working with Java 10, assuming the XSD file path is src/main/xsd/schema.xsd:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>...</groupId>
	<artifactId>...</artifactId>
	<version>...</version>
	<packaging>jar</packaging>
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<maven.compiler.source>10</maven.compiler.source>
		<maven.compiler.target>10</maven.compiler.target>
	</properties>
	<!-- ... -->
	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-antrun-plugin</artifactId>
				<version>1.7</version>
				<executions>
					<execution>
						<phase>initialize</phase>
						<goals>
							<goal>run</goal>
						</goals>						
						<configuration>
							<tasks>
								<mkdir dir="target/generated-sources"/>
							</tasks>
						</configuration>
					</execution>
				</executions>
			</plugin>
			<plugin>
				<groupId>org.codehaus.mojo</groupId>
				<artifactId>exec-maven-plugin</artifactId>
				<version>1.5.0</version>
				<executions>
					<execution>
						<phase>generate-sources</phase>
						<goals>
							<goal>exec</goal>
						</goals>
					</execution>
				</executions>
				<configuration>
					<executable>xjc</executable>
					<arguments>
						<argument>-p</argument>
						<argument>some.package</argument>
						<argument>-d</argument>
						<argument>target/generated-sources</argument>
						<argument>src/main/xsd/schema.xsd</argument>
					</arguments>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.codehaus.mojo</groupId>
				<artifactId>build-helper-maven-plugin</artifactId>
				<version>3.0.0</version>
				<executions>
					<execution>
						<phase>process-sources</phase>
						<goals>
							<goal>add-source</goal>
						</goals>
						<configuration>
							<sources>
								<source>target/generated-sources</source>
							</sources>
						</configuration>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
</project>

The last thing to mention is that we need an additional dependency to jaxb-api – this solution should work even with Java 11 (hopefully…):

<dependency>
	<groupId>javax.xml.bind</groupId>
	<artifactId>jaxb-api</artifactId>
	<version>2.3.0</version>
</dependency>

Ufff… Or you can just return to Java 8 instead. ๐Ÿ™‚

Advertisements
Posted in Java | Tagged , , | 2 Comments

amd_iommu=off or amd_iommu=fullflush

Hundreds of years ago the poet William Shakespeare wrote:

To be, or not to be?

Today, users of some HP Notebook laptops with AMD CPU (like HP Notebook 15-ba006nm) wanting to have Linux often have different dilemma:

amd_iommu=off or amd_iommu=fullflush ?

As I experienced myself, Linux with kernel in version between 4.8 and 4.12 has problems to boot on such laptops. The solution that I found in September 2017 was to add following boot-parameter for kernel: amd_iommu=off. But as I’ve recently discovered the 2nd variant (amd_iommu=fullflush) helps as well in this situation (verified with Linux Mint 18.3 LTS).

The problem with the 1st variant (amd_iommu=off) is that it turns off the IOMMU. I can bet this is not obvious for many people what the hell is this “IOMMU”? And if it can safely be turned off?

In practice you can live without IOMMU – as I did. Actually nothing changes in normal, daily using of a computer (my impression).

But only last days I’ve learned more about the IOMMU. Especially this page was very helpful: IOMMU: Virtualizing IO through IO Memory Management Unit (IOMMU), Use Cases and Internals of IOMMU. The title says about virtualization however it’s not what I see as the most important thing related to IOMMU. Thanks to the presentation found on this page, I have learned that the IOMMU is a piece of hardware that is important from the security point of view. It’s because without IOMMU:

  1. there is no protection from malicious (or vulnerable?) devices (DMA Attack)
  2. there is no protection from buggy device drivers – so poor driver can destabilize your system or even cause some corruption

There are more, but the 2 points above I see as the most important advantages of using IOMMU.

Of course there are other ways the IOMMU functionality can be… emulated. For example by OS software (bounce buffer). But it doesn’t perform as good as IOMMU – because the IOMMU is hardware. And I’m not sure if a software solution is as safe as IOMMU.

Conclusion

If you find yourself in a situation that you have to add amd_iommu=off as parameter for kernel to boot your Linux first try if this parameter instead does the job:

amd_iommu=fullflush

As the value suggests it should make that IOMMU is used, what is safer than turning IOMMU off. So dilemma solved! ๐Ÿ™‚

How to check if IOMMU is used?

Examine output of the following command:

dmesg|grep -i iommu

If there is some output and it doesn’t mention any warning or error then it’s good.

Good news!

If you have such a problem with booting Linux on your computer that was solved only by adding kernel boot-param amd_iommu=off then try newer Linux version! Ubuntu 18.04 LTS has kernel 4.15 and the problem is gone on my HP laptop! ๐Ÿ™‚

Posted in Linux, security, hardware | Tagged , , | 1 Comment

RabbitMQ message listener in Spring Boot

Last time I was introducing a RabbitMQ message receiver in an application using Spring Boot 1.5.4. To match the version of the message broker in an organisation I used spring-rabbit 1.7.3. As I was interested in receiving messages from a queue in a transaction I’ve quickly found the blog-post Using transactions with RabbitMQ and SQL database in Spring Boot application. The example of the message listener bean given there is:

@Component
@Transactional
@RabbitListener(queues = {"myqueue"})
public class RabbitReceiver {

    @RabbitHandler
    public void receive(String event) {
        //...
    }
}

The problem is this doesn’t work! The application was not receiving messages from a RabbitMQ queue which were successfully sent and were visible in RabbitMQ Management Console.

Solution

I’ve changed this bean in such a way:

@Component
public class RabbitReceiver {

    @Transactional
    @RabbitListener(queues = {"myqueue"})
    public void receive(String event) {
        //...
    }
}

…and things started to work!. Switching to @RabbitListener annotation at the method level solved the problem!

BTW: apart from the above problem the mentioned blog-post is a good example of implementing RabbitMQ message sender and message listener in a Spring Boot application, so you can refer to it for other details.

Posted in Java, Spring | Tagged , | Leave a comment

Laptop’s screen blank after detaching from a docking station

On Linux Mint 18.3 64-bit with MATE 1.18 running on Lenovo ThinkPad L470 laptop I’m experiencing the blank screen after detaching the laptop from a docking station. Usually the scenario is like that:

  1. laptop is sitting on a docking station and after longer time the screen goes blank according to power saving rules
  2. I’m detaching the laptop from a docking station while the screen is blank or I’m closing the lid and then detaching
  3. the laptop’s screen stays blank and looks like frozen or like it cannot wake up from sleep mode

I’ve got a monitor connected to the docking station and I’m using 2 screens when laptop is docked. And sometimes I’m experiencing an other variant of the problem:

  1. after undocking the Linux Mint is behaving like still having 2 screens thus I only see windows that were on laptop’s built-in screen before undocking

Solution

In both described scenarios this single solution helps:

  1. Press Ctrl+Alt+F1
  2. Wait for the text console login prompt to appear
  3. Press Alt+F7

That’s all ๐Ÿ™‚

Posted in Linux | Leave a comment

Docker-compose, Windows 10/Linux/Bamboo and containers’ IP address

Last time I was playing a little bit with setting up a Docker-compose environment with couple of applications running in separate containers and communicating with them from the host machine. A program running on a host machine needed to know IP address and port number mapped to a given containerized application. The aim was to prepare an infrastructure in an OS-independent way. Unfortunately it looks that Docker-compose for Linux works a little bit different that Docker-compose for Windows (at least in Docker Toolbox variant).

Containers were configured to use network mode “bridge”, so containerized applications could communicate between each other. Each container exposed one port that should be mapped by Docker-compose to a dynamically allocated port accessible from the host machine. Those ports can be easily established based on the output of docker-compose ps command.

How to establish IP address?

Please note that we’re not interested in internal IP addresses of containers used in inter-container communication. We would like to know the IP address used from the host machine to communicate with containers.

Windows

It turned out that under Windows (Windows 10, Docker Toolbox for Windows) to establish IP address that is used on the host machine to communicate with containerized applications one needs to use the docker-machine command:

docker-machine ip

The IP address returned by this command is the one assigned to a virtual machine created internally by Docker-compose on Windows to implement containers. And this is a kind of a surprise for beginners.

Linux

On the other hand, under Linux, the IP address used on the host machine to communicate with containerized applications is just… a local host address 127.0.0.1 (or localhost).

But wait! This doesn’t work when Docker containers are started by a job on Atlassian Bamboo server which itself is running under Linux. I was facing “connection refused” error in this case. So according to point 2 of step 4 in “Get started with Docker Compose” document (official Docker documentation!) there is a second option: use IP address of 0.0.0.0

This worked on my computer with Linux but again it didn’t work in Atlassian Bamboo environment which seemed to be Linux environment! But it looks like Bamboo agents are running in Docker. Or at least they can run in Docker (Bamboo server was out of my control so I wasn’t sure). So it’s possible this was a case of running Docker containers inside a Docker container!

Solution for Linux and for Atlassian Bamboo

The universal solution for establishing correct IP that works under Linux and in Atlassian Bamboo (if it runs under Linux) is to determine the IP of a network interface created by Docker to provide its network mode “bridge”. There are couple of ways how to determine:

  1. Use command docker network inspect bridge and look for line with “Gateway” (in the example below the IP is 172.17.0.1):
    $ docker network inspect bridge
    [
        {
            "Name": "bridge",
            "Id": "7f08d9b766b7ac71c6a87f049f2e9908137d03fd4e5ea682f3d7b9009359f756",
            "Created": "2018-02-21T17:02:29.521034216+01:00",
            "Scope": "local",
            "Driver": "bridge",
            "EnableIPv6": false,
            "IPAM": {
                "Driver": "default",
                "Options": null,
                "Config": [
                    {
                        "Subnet": "172.17.0.0/16",
                        "Gateway": "172.17.0.1"
                    }
                ]
            },
            "Internal": false,
            "Attachable": false,
            "Containers": {},
            "Options": {
                "com.docker.network.bridge.default_bridge": "true",
                "com.docker.network.bridge.enable_icc": "true",
                "com.docker.network.bridge.enable_ip_masquerade": "true",
                "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
                "com.docker.network.bridge.name": "docker0",
                "com.docker.network.driver.mtu": "1500"
            },
            "Labels": {}
        }
    ]
    
  2. Use command ifconfig and look for something like docker0 interface:
    $ ifconfig
    docker0   Link encap:Ethernet  HWaddr 01:41:16:d1:e1:01  
              inet addr:172.17.0.1  Bcast:0.0.0.0  Mask:255.255.0.0
              UP BROADCAST MULTICAST  MTU:1500  Metric:1
              RX packets:0 errors:0 dropped:0 overruns:0 frame:0
              TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:0 
              RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
    ...
    
  3. Use “docker inspect” command with ID of any of your running Docker containers and look for NetworkSettings.Gateway property. Sample output.
  4. If any of above methods is not available (still possible under Bamboo) then use Docker-client library made by Spotify. For me this Java code worked to get the IP:
    DockerClient dockerClient = DefaultDockerClient.fromEnv().build();
    ContainerInfo info = dockerClient.inspectContainer(dockerContainerId);
    String ipAddress = info.networkSettings().gateway();
    

This single approach of establishing IP to communicate with Docker containers worked for me if my environment setup script just detected Linux, no matter if it was running on my Linux box or under Bamboo (running under Linux as well).

Summary

Docker-compose is mostly great in unifying runtime environment however establishing IP address to communicate with containers from outside of Docker is still not unified. The problems are not only introduced by Windows OS. The case I’ve experienced with Atlassian Bamboo shows network related problem with Docker can appear in other circumstances as well. :-\

Posted in Docker, Linux | Tagged , , , , | Leave a comment

No Windows in boot menu after installing Linux Mint 18.3

Last days I needed to install Linux on a computer having pre-installed Windows. I wasn’t installing Linux next to Windows for many years and the previous time it was a plain PC with BIOS and Windows XP and all went well.

But this time… this time it was a laptop (Lenovo ThinkPad L470) with UEFI (What it’s all about UEFI vs BIOS?) and Windows 10. And this time after installing Linux Mint 18.3 I was surprised to notice that Grub menu is missing Windows entry! And BIOS (UEFI?) option to boot Windows Boot Loader didn’t work. Apparently I was left with no way to boot Windows 10 again.

Solution

In my case it was enough to boot the installed Linux, open a terminal and execute this command:

sudo update-grub

After this, on the next start/reboot of the computer, the Grub menu contained the entry “Windows 10” and Windows was booting correctly when selected. Voila!

Posted in Linux | Tagged , , , | Leave a comment

Spring Framework and uber-jar made by maven-shade-plugin

If you’re trying to build a Java application in a form of an uber-jar with use of Spring Framework, maven and maven-shade-plugin and you see an error similar to the below one (BeanDefinitionParsingException: Configuration problem: Unable to locate Spring NamespaceHandler for XML schema namespace) after running the application then this article is for you.

org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Unable to locate Spring NamespaceHandler for XML schema namespace [http://www.springframework.org/schema/context]
Offending resource: class path resource [app-context.xml]

	at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:70)
	at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:118)
	at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:110)
	at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.error(BeanDefinitionParserDelegate.java:301)
	at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1407)
	at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1400)
	at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:172)
	at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:142)
	at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:94)
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:508)
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:392)
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:336)
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:304)
	at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:181)
	at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:217)
	at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:188)
	at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:125)
	at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:94)
	at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:129)
	at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:614)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:515)
	...

Solution

The solution is to extend maven-shade-plugin configuration in your pom.xml as given in documentation for maven-shade-plugin Resource Transformers. The important part to add is:

<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
    <resource>META-INF/spring.handlers</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
    <resource>META-INF/spring.schemas</resource>
</transformer>

The complete configuration of maven-shade-plugin is therefore something like this:

<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-shade-plugin</artifactId>
	<version>3.1.0</version>
	<executions>
	    <execution>
		<phase>package</phase>
		<goals>
		    <goal>shade</goal>
		</goals>
		<configuration>
		    <createDependencyReducedPom>false</createDependencyReducedPom>
		    <transformers>
		        <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
		            <mainClass>fully.qualified.your.main.class</mainClass>
		        </transformer>
		        <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
		            <resource>META-INF/spring.handlers</resource>
		        </transformer>
		        <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
		            <resource>META-INF/spring.schemas</resource>
		        </transformer>
		    </transformers>
		    <filters>
		        <filter>
		            <artifact>*:*</artifact>
		            <excludes>
		                <exclude>META-INF/*.SF</exclude>
		                <exclude>META-INF/*.DSA</exclude>
		                <exclude>META-INF/*.RSA</exclude>
		            </excludes>
		        </filter>
		    </filters>
		</configuration>
	    </execution>
	</executions>
</plugin>

The above worked for me. Parameters <filters> and <createDependencyReducedPom/> were accompanying some sample plugin configuration I found and they’re not breaking things in my case.

Posted in Java, Spring | Tagged , , | Leave a comment