BAEL-5951: Spring Boot 3 Sample for Native Image builds incl. Runtime Hints (#13047)

* Update Spring Boot, Spring Native and Native Maven Plugin versions

* BAEL-5951: Spring Boot 3 Sample for Native Image builds incl. Runtime Hints

* BAEL-5951: Configure POMs and add Swagger UI runtime hints

* BAEL-5951: Remove Swagger UI runtime hints

* BAEL-5951: Remove Spring Boot3 parent POM from profiles because of JDK17 dependency during build (building the parent POM is even not necessary)

* BAEL-5951: Add tests

* BAEL-5951: Fix tests (PMD naming conventions)
This commit is contained in:
Ralf Ueberfuhr
2022-11-24 09:47:54 +01:00
committed by GitHub
parent d1e0a4cefe
commit b913e47c13
16 changed files with 494 additions and 24 deletions
@@ -0,0 +1,23 @@
package com.baeldung.sample;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class BoundaryConfiguration {
@Bean
public WebMvcConfigurer webMvcConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry
.addViewController("/")
.setViewName("redirect:/index.html");
}
};
}
}
@@ -0,0 +1,22 @@
package com.baeldung.sample;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportRuntimeHints;
@ImportRuntimeHints(GraphQlRuntimeHints.GraphQlResourcesRegistrar.class)
@Configuration
public class GraphQlRuntimeHints {
static class GraphQlResourcesRegistrar implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
hints.resources()
.registerPattern("graphql/**/")
.registerPattern("graphiql/index.html");
}
}
}
@@ -0,0 +1,30 @@
package com.baeldung.sample;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportRuntimeHints;
@Configuration
@ImportRuntimeHints(JacksonRuntimeHints.PropertyNamingStrategyRegistrar.class)
public class JacksonRuntimeHints {
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(JacksonRuntimeHints.class);
static class PropertyNamingStrategyRegistrar implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
try {
hints
.reflection()
.registerField(PropertyNamingStrategies.class.getDeclaredField("SNAKE_CASE"));
log.info("Registered native hint for SNAKE_CASE!");
} catch (NoSuchFieldException e) {
log.warn("Unable to register native hint for SNAKE_CASE!");
}
}
}
}
@@ -0,0 +1,11 @@
package com.baeldung.sample;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class TodoApplication {
public static void main(String[] args) {
SpringApplication.run(TodoApplication.class, args);
}
}
@@ -0,0 +1,31 @@
package com.baeldung.sample;
public class User {
private String firstName;
private String lastName;
public User(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public User() {
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
@@ -0,0 +1,19 @@
package com.baeldung.sample;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/v1/user")
public class UserController {
@QueryMapping("getUser")
@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
public User getUser() {
return new User("John", "Doe");
}
}
@@ -0,0 +1,6 @@
spring:
graphql:
graphiql:
enabled: true
jackson:
property-naming-strategy: SNAKE_CASE
@@ -0,0 +1,8 @@
type User {
firstName: String!
lastName: String!
}
type Query {
getUser: User!
}
@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Spring Native Demo Application</title>
</head>
<body>
<h1>Spring Native Demo Application</h1>
<p>
This is a sample application that can be built as native executable.
</p>
<ul>
<li><a href="./swagger-ui.html">REST API Test Client</a></li>
<li><a href="./graphiql">GraphQL API Test Client</a></li>
</ul>
</body>
</html>
@@ -0,0 +1,23 @@
package com.baeldung.sample;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest
class JacksonAutoConfigurationIntegrationTest {
@Autowired
ObjectMapper mapper;
@Test
void shouldUseSnakeCasePropertyNamingStrategy() {
assertThat(mapper.getPropertyNamingStrategy())
.isSameAs(PropertyNamingStrategies.SNAKE_CASE);
}
}
@@ -0,0 +1,27 @@
package com.baeldung.sample;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import org.junit.jupiter.api.Test;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
import static org.assertj.core.api.Assertions.assertThat;
class JacksonRuntimeHintsUnitTest {
@Test
void shouldRegisterSnakeCasePropertyNamingStrategy() {
// arrange
final var hints = new RuntimeHints();
final var expectSnakeCaseHint = RuntimeHintsPredicates
.reflection()
.onField(PropertyNamingStrategies.class, "SNAKE_CASE");
// act
new JacksonRuntimeHints.PropertyNamingStrategyRegistrar()
.registerHints(hints, getClass().getClassLoader());
// assert
assertThat(expectSnakeCaseHint).accepts(hints);
}
}