For Josh’s examples, see his Spring Native 0.11.x repo.
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 Spring Native support:<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.11.2</spring-native.version> ... <!-- 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.9</native-buildtools.version> </properties> <dependencies> <dependency> <groupId>org.junit.platform</groupId> <artifactId>junit-platform-launcher</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.graalvm.buildtools</groupId> <artifactId>native-maven-plugin</artifactId> <version>${native-buildtools.version}</version> <extensions>true</extensions> <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>
-
Delete
src/main/resources/logback-spring.xml
and tone down logging. Removesrc/test/resources/logback.xml
too.logging: level: root: ERROR io.netty: ERROR org.springframework: INFO
-
There’s an issue when using Spring WebFlux if you don’t use
-DskipTests
when running./mvnw package -Pnative
:[ERROR] Failed to execute goal org.springframework.experimental:spring-aot-maven-plugin:0.11.2:test-generate (test-generate) on project jhipster: Build failed during Spring AOT test code generation: Unable to execute mojo: Unable to parse configuration of mojo org.apache.maven.plugins:maven-compiler-plugin:3.9.0:testCompile for parameter compilePath: Cannot find 'compilePath' in class org.apache.maven.plugin.compiler.TestCompilerMojo -> [Help 1] [ERROR]
The error seems to be better when using Spring MVC:
Caused by: java.lang.IllegalStateException: @MockBean is not supported yet by Spring AOT and has been detected on type org.springframework.web.client.RestTemplate
-
If using Spring MVC, swap Undertow dependencies for Tomcat (in
pom.xml
) and modifyWebConfigurer
to comment outsetLocationForStaticAssets(server)
. -
Update main
App.java
to add hints for Micrometerimport org.springframework.nativex.hint.TypeHint; @TypeHint( types = { org.HdrHistogram.Histogram.class, org.HdrHistogram.ConcurrentHistogram.class })
-
Add springdocs native dependency:
<dependency> <groupId>org.springdoc</groupId> <artifactId>springdoc-openapi-native</artifactId> <version>1.6.5</version> </dependency>
+ And update
jhipster-dependencies
to7.6.1-SNAPSHOT
(since it specifies 1.6.5). With 1.6.2, the following error happens:Parameter 0 of constructor in org.springdoc.nativex.core.SpringDocHints required a bean of type 'org.springdoc.core.SwaggerUiConfigProperties' that could not be found.
Swagger doesn’t seem to work with WebFlux. In my browser’s console, it says:
Failed to load resource: the server responded with a status of 404 :8080/management/jhiopenapigroups
-
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 type hints for Liquibase and related classes.
@TypeHint( types = { ... liquibase.configuration.LiquibaseConfiguration.class, com.zaxxer.hikari.HikariDataSource.class, liquibase.change.core.LoadDataColumnConfig.class, tech.jhipster.domain.util.FixedPostgreSQL10Dialect.class, org.hibernate.type.TextType.class })
-
If you’re using JPA, configure Hibernate build-time bytecode enhancement. Add the plugin right after the
spring-aot-maven-plugin
.In
application.yml
, turn off loading of SQL so Liquibase works:spring: ... sql: init: mode: never
Without this change, the following error happens:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSourceScriptDatabaseInitializer': Circular depends-on relationship between 'dataSourceScriptDatabaseInitializer' and 'liquibase'
-
Build with
./mvnw package -Pnative,prod -DskipTests
-
If you’re using Spring WebFlux with R2DBC, we haven’t figured that one out yet.
-
If Spring MVC, add names to any
@RequestParam
and@PathVariable
annotations.@RequestParam(name = "eagerload", required = false, defaultValue = "false") boolean eagerload @PathVariable("id") Long id
-
For logout to work, update
LogoutResource
to remove(expression = "idToken")
, inject theOidcUser
instead, and get the token from there:public ResponseEntity<?> logout(HttpServletRequest request, @AuthenticationPrincipal OidcUser oidcUser) { ... OidcIdToken idToken = oidcUser.getIdToken();
-
-DskipTests
is needed for both Spring MVC and WebFlux. This seems to be caused by Mockito. -
Creating a new
Post
orTag
in thepostgres-mvc
project doesn’t work. The error is:Caused by: com.fasterxml.jackson.databind.JsonMappingException: Unable to perform requested lazy initialization [com.mycompany.myapp.domain.Post.tags] - no session and settings disallow loading outside the Session (through reference chain: java.util.Collections$UnmodifiableRandomAccessList[0]->com.mycompany.myapp.domain.Post["tags"])
-
Several of JHipster’s Administration features don’t work: metrics, logs, API docs, and configuration.
-
Metrics:
UnsupportedFeatureError: ThreadMXBean methods
-
Logs:
/management/loggers
returns HTML instead of JSON -
Configuration:
org.springframework.http.converter.HttpMessageNotWritableException: No converter for [class org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpoint$ApplicationConfigurationProperties] with preset Content-Type 'null'
-
H2 doesn’t work
java.lang.IllegalStateException: Failed to process lifecycle methods on bean definition with name 'h2TCPServer'
It might be possible to fix with a
@TypeHint
fororg.h2.tools.Server.class
. However, this class is not on the classpath by default.