Hola!
When using the maven shade plugin with Spring Boot and other spring dependencies, enabling minimizeJar results in ClassNotFoundExceptions being thrown. An example application can be seen in this repository where I have copied the plugin config out of the parent and added the appropriate tag, with the below stack trace:
Click to view stack trace
$ java -jar ./demo-0.0.1-SNAPSHOT.jar
Exception in thread "main" java.lang.IllegalArgumentException: Cannot instantiate interface org.springframework.boot.BootstrapRegistryInitializer : org.springframework.cloud.bootstrap.RefreshBootstrapRegistryInitializer
at org.springframework.boot.SpringApplication.createSpringFactoriesInstances(SpringApplication.java:449)
at org.springframework.boot.SpringApplication.getSpringFactoriesInstances(SpringApplication.java:431)
at org.springframework.boot.SpringApplication.getSpringFactoriesInstances(SpringApplication.java:424)
at org.springframework.boot.SpringApplication.<init>(SpringApplication.java:266)
at org.springframework.boot.SpringApplication.<init>(SpringApplication.java:246)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295)
at com.jbarlin.example.demo.ConfigServerApplication.main(ConfigServerApplication.java:12)
Caused by: java.lang.ClassNotFoundException: org.springframework.cloud.bootstrap.RefreshBootstrapRegistryInitializer
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:488)
at java.base/java.lang.Class.forName(Class.java:467)
at org.springframework.util.ClassUtils.forName(ClassUtils.java:284)
at org.springframework.boot.SpringApplication.createSpringFactoriesInstances(SpringApplication.java:442)
... 7 more
This issue does not occur if you set the minimizeJar to false and the server continues to start
From the looks of things, the PropertiesMergingResourceTransformer isn't marking classes listed in the spring.factories as being needed in a minimized Jar - indeed, it doesn't really look like there is a way to do so within the plugin itself except for making a META-INF/services/ file with the appropriate entries
Is this something that spring boot wishes to support? If so, I can start working implementing that solution (or a better one, if someone can think of one) if you are happy for me to do so? Alternatively, if this is something that isn't going to be supported, is there a possibility of writing it somewhere in the documentation?
Comment From: wilkinsona
Is this something that spring boot wishes to support?
I don't think we've thought about it until now. If it can be made to work reliably then we can certainly consider it.
the
PropertiesMergingResourceTransformerisn't marking classes listed in the spring.factories as being needed in a minimized Jar
I can't see how a ResourceTransformer can do that. Looking at org.apache.maven.plugins.shade.filter.MinijarFilter and its use in ShadeMojo, minimising a jar doesn't appear to be very configurable or extensible. It's not clear to me that we can tell the shading process to keep additional classes when minimizeJar has been set to true. If I've overlooked something and it is, in fact, possible, I'd be happy to review something that implements it.
Comment From: jbarlin
Looking through it, my original plan was to simply modify the PropertiesMergingResourceTransformer to also create a META-INF\services entry for each factory while processing, but digging through the work that's been undertaken within spring-native, it looks like there's possibly a bit more going on than what I could reasonably do.
I'll leave it to you to decide if you want to close this or leave it open for a future task for someone to do
Comment From: wilkinsona
We wouldn't want to add fake services entries as there's no guarantee that a class listed in spring.factories is suitable for creation via the service loader mechanism. Given that's not an option, I don't think Maven's Shade plugin is sufficiently extensible to allow us to do this. I'll close this one for now. We can reconsider it should Shade ever be improved in this area.