Spring Native with JHipster
This repository contains five apps we (@joshlong and @mraible) used to figure out how to make Spring Native work with JHipster.
-
spring-native-webflux
- no client, no db, just WebFlux -
spring-native-mvc
- no client, no db, just Spring MVC -
angular-webflux
- Angular client, no db -
postgres-webflux
- Angular, WebFlux, R2DBC + PostgreSQL -
postgres-mvc
- Angular, Spring MVC, JPA + PostgreSQL
You should be able to create a JHipster monolith with OIDC, then make the following changes.
-
Modify
pom.xml
to add native, adjust dependencies, and disable devtools:<repository> <id>spring-releases</id> <name>Spring Releases</name> <url>https://repo.spring.io/release</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> <pluginRepository> <id>spring-releases</id> <name>Spring Releases</name> <url>https://repo.spring.io/release</url> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> ... <repackage.classifier/> <spring-native.version>0.10.4</spring-native.version> ... <!-- Comment out devtools --> <!--dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency--> <!-- If reactive, add the following to fix NoClassDefFoundError: org/springframework/web/servlet/config/annotation/WebMvcConfigurer --> <!-- Answer from https://stackoverflow.com/a/67426209/65681 --> <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> ... <!-- Springfox doesn't have support for Spring Native yet, so comment out Springfox dependencies --> <!-- https://github.com/springfox/springfox/issues/3816 --> ... <!-- If reactive, comment out boringssl. This allows Spring Native to build the image and gets around this error: 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). To see why io.netty.buffer.UnpooledUnsafeDirectByteB got initialized use trace-class-initialization=io.netty.buffer.UnpooledUnsafeDirectByteBuf --> <!--dependency> <groupId>io.netty</groupId> <artifactId>netty-tcnative-boringssl-static</artifactId> </dependency--> <dependency> <groupId>org.springframework.experimental</groupId> <artifactId>spring-native</artifactId> <version>${spring-native.version}</version> </dependency> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <classifier>${repackage.classifier}</classifier> <image> <builder>paketobuildpacks/builder:tiny</builder> <env> <BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE> </env> </image> </configuration> </plugin> <plugin> <groupId>org.springframework.experimental</groupId> <artifactId>spring-aot-maven-plugin</artifactId> <version>${spring-native.version}</version> <executions> <execution> <id>test-generate</id> <goals> <goal>test-generate</goal> </goals> </execution> <execution> <id>generate</id> <goals> <goal>generate</goal> </goals> </execution> </executions> </plugin> <profile> <id>native</id> <properties> <repackage.classifier>exec</repackage.classifier> <native-buildtools.version>0.9.3</native-buildtools.version> </properties> <dependencies> <dependency> <groupId>org.graalvm.buildtools</groupId> <artifactId>junit-platform-native</artifactId> <version>${native-buildtools.version}</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.graalvm.buildtools</groupId> <artifactId>native-maven-plugin</artifactId> <version>${native-buildtools.version}</version> <executions> <execution> <id>test-native</id> <phase>test</phase> <goals> <goal>test</goal> </goals> </execution> <execution> <id>build-native</id> <phase>package</phase> <goals> <goal>build</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </profile>
-
Remove the
127.0.0.1
prefix fromkeycloak.yml
-
Delete
spring-logback.xml
and tone down logginglogging: level: root: ERROR
-
If reactive, update
LocaleConfiguration.java
to remove@Import(WebFluxAutoConfiguration.class)
-
Update main
App.java
to add hints (first four of each list only required for reactive)@NativeHint(options = "--enable-url-protocols=http,https") @TypeHint( types = { ReactiveOAuth2AuthorizedClientManager.class, ReactiveOAuth2AuthorizedClientProviderBuilder.class, DefaultReactiveOAuth2AuthorizedClientManager.class, AbstractWebClientReactiveOAuth2AccessTokenResponseClient.class, liquibase.configuration.LiquibaseConfiguration.class, com.zaxxer.hikari.HikariDataSource.class, liquibase.change.core.LoadDataColumnConfig.class, org.HdrHistogram.Histogram.class, org.HdrHistogram.ConcurrentHistogram.class, }, typeNames = { "org.springframework.web.reactive.function.client.DefaultWebClientBuilder", "reactor.core.publisher.Traces$StackWalkerCallSiteSupplierFactory", "reactor.core.publisher.Traces$SharedSecretsCallSiteSupplierFactory", "reactor.core.publisher.Traces$ExceptionCallSiteSupplierFactory", "com.zaxxer.hikari.util.ConcurrentBag$IConcurrentBagEntry[]" }, access = AccessBits.ALL)
-
Liquibase is not supported yet, but you can make it work by adding files from this pull request to your
src/main/resources/META-INF/native-image/liquibase
directory -
Add an
@AotProxyHint
for each Resource classes@AotProxyHint(targetClass = UserResource.class, proxyFeatures = ProxyBits.IS_STATIC) @AotProxyHint(targetClass = BlogResource.class, proxyFeatures = ProxyBits.IS_STATIC) @AotProxyHint(targetClass = PostResource.class, proxyFeatures = ProxyBits.IS_STATIC) @AotProxyHint(targetClass = TagResource.class, proxyFeatures = ProxyBits.IS_STATIC)
-
If using Spring WebFlux, refactor repositories and add
@AotProxyHint
for each one -
If using Spring MVC, swap Undertow dependencies for Tomcat, modify
WebConfigurer
to comment outsetLocationForStaticAssets(server)
, and add additional type hints for the following classes:-
tech.jhipster.domain.util.FixedPostgreSQL10Dialect.class
-
org.hibernate.type.TextType.class
-
-
Build with
./mvnw package -Pnative,prod -DskipTests
Known Issues
-
Springfox (Swagger) doesn’t work
-
Metrics don’t work
-
Repositories need refactoring for R2DBC