JHipster Works with Spring Native!
When I flew to San Francisco this week, I was cautiously optimistic about the task ahead. My goal was to speak at the San Francisco Java User Group (JUG) about Spring Native and JHipster with my good friend, Josh Long.
I was a bit nervous because Spring Native didn't work with JHipster. I'd been trying to make it work since January of this year.
However, I was inspired by recent work I'd done with Josh and my colleague, Brian Demers. We did a live Twitch stream in June and figured out how to make the Okta Spring Boot starter work with Spring Native.
Josh and I started hacking on things Tuesday morning. We began with a super simple JHipster app that had no client and no database. After adding Spring Native support to our build file, we found that we had to comment out Spring Boot's DevTools since it's not supported yet. Next, we removed Springfox dependencies, since it doesn't support Spring Native yet.
We removed src/main/resources/spring-logback.xml because Spring Native notified us it wasn't supported. Because this increased the logging quite a bit, I toned it down in application-dev.yml and application-prod.yml files.
logging: level: root: ERROR
Then we got into some obscure stuff. For example:
Error: Classes that should be initialized at run time got initialized during image building: io.netty.buffer.UnpooledUnsafeDirectByteBuf the class was requested to be initialized at run time (subtype of io.netty.buffer.AbstractReferenceCountedByteBuf).
This turned out to be caused by Netty's netty-tcnative-boringssl-static dependency. Removing it from our build file fixed the problem.
We also had to remove @Import(WebFluxAutoConfiguration.class) from LocaleConfiguration.
The error that really baffled us was the following:
NoClassDefFoundError: org/springframework/web/servlet/config/annotation/WebMvcConfigurer
This seemed really strange since we didn't have spring-webmvc as a dependency. We found the fix on Stack Overflow and had a good chuckle.
I'm not happy with it, but this is a workaround. Adding the following piece of code in the pom.xml file:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency>
Finally, we had to add a number of hints for Spring Native to enable HTTP, HTTPS, and to specify classes used by Spring Security OAuth.
@NativeHint(options = "--enable-url-protocols=http,https") @TypeHint( types = { ReactiveOAuth2AuthorizedClientManager.class, ReactiveOAuth2AuthorizedClientProviderBuilder.class, DefaultReactiveOAuth2AuthorizedClientManager.class, AbstractWebClientReactiveOAuth2AccessTokenResponseClient.class }, typeNames = { "org.springframework.web.reactive.function.client.DefaultWebClientBuilder", "reactor.core.publisher.Traces$StackWalkerCallSiteSupplierFactory", "reactor.core.publisher.Traces$SharedSecretsCallSiteSupplierFactory", "reactor.core.publisher.Traces$ExceptionCallSiteSupplierFactory" }, access = AccessBits.ALL)
Spring Native notified us about many of these, but we didn't discover the issues until we'd built and run the app. That means we'd make a change, build the image, and run it. This cycle took 6-10 minutes each time, so it was quite a tedious process. We paired the whole time on it, broadcasting the laptop screen to a TV for convenience.
When we first succeeded, we were tickled to death and rejoiced in our victory! We quickly realized there was more work to do:
- Make Spring Native + JHipster work with a client, like Angular
- Make it work with a database, like PostgreSQL
- Make it work with Spring MVC
- Make it work with entities (R2DBC for WebFlux and JPA for Spring MVC)
I'm happy to report that we succeeded in figuring out how to make all these combinations work over the next 24 hours. We finished about an hour before our talk was scheduled to begin for the SF JUG.
We documented all the things we learned in a GitHub project called spring-native-samples.
We created a single slide for our presentation and delivered our talk. The talk was recorded, so I'll add the video here when it's published. In the meantime, please try your JHipster apps with our instructions and send us a PR if you find anything that needs changing.
NOTE: We did use a nightly build of JHipster to create our apps, so we could use the latest version of Spring Boot (2.5.5) and Spring Native (0.10.4).
I'd like to thank Josh for all his help getting Spring Native to work on the Okta Spring Boot starter and JHipster. It sure is nice having a friend in the know!
Update: You can find a recording of our presentation on YouTube.
Update 2: JHipster now has a Spring Native blueprint! Please see Introducing Spring Native for JHipster for more information.
Senior Java Developer na Risk Control Limited
2yNice milestone!
IT Engineering Manager | PRINCE2® | SAFe® POPM |
2yGreat success! I can't wait to try ;)
Solution Architect @ Key Consulting Group
2yAmazing job to you two for this long awaited feature on JHipster native image support with GraalVM and Spring Native. Looking forward to testing it!