Skip to content

Commit 1db674c

Browse files
authored
Merge pull request #166 from tnaskali/chore/migrate-to-spring-boot-4
chore: migrate to Spring Boot 4.0.0
2 parents 4d7a647 + ed389d4 commit 1db674c

30 files changed

+142
-158
lines changed

pom.xml

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<parent>
66
<groupId>org.springframework.boot</groupId>
77
<artifactId>spring-boot-starter-parent</artifactId>
8-
<version>3.5.7</version>
8+
<version>4.0.0</version>
99
<relativePath/>
1010
</parent>
1111

@@ -110,10 +110,6 @@
110110
</dependencyManagement>
111111

112112
<dependencies>
113-
<dependency>
114-
<groupId>com.fasterxml.jackson.datatype</groupId>
115-
<artifactId>jackson-datatype-jsr310</artifactId>
116-
</dependency>
117113
<dependency>
118114
<groupId>com.github.ben-manes.caffeine</groupId>
119115
<artifactId>caffeine</artifactId>
@@ -162,6 +158,10 @@
162158
<groupId>org.springframework.boot</groupId>
163159
<artifactId>spring-boot-starter-graphql</artifactId>
164160
</dependency>
161+
<dependency>
162+
<groupId>org.springframework.boot</groupId>
163+
<artifactId>spring-boot-starter-jackson</artifactId>
164+
</dependency>
165165
<dependency>
166166
<groupId>org.springframework.boot</groupId>
167167
<artifactId>spring-boot-starter-logging</artifactId>
@@ -170,6 +170,10 @@
170170
<groupId>org.springframework.boot</groupId>
171171
<artifactId>spring-boot-starter-security</artifactId>
172172
</dependency>
173+
<dependency>
174+
<groupId>org.springframework.boot</groupId>
175+
<artifactId>spring-boot-starter-webclient</artifactId>
176+
</dependency>
173177
<dependency>
174178
<groupId>org.springframework.boot</groupId>
175179
<artifactId>spring-boot-starter-webflux</artifactId>

src/main/java/li/naska/bgg/configuration/CacheConfiguration.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@
2121
public class CacheConfiguration {
2222

2323
@Bean
24-
public Caffeine<Object, Object> caffeineConfig() {
24+
public Caffeine<@NotNull Object, @NotNull Object> caffeineConfig() {
2525
return Caffeine.newBuilder().maximumSize(100).expireAfterWrite(60, TimeUnit.SECONDS);
2626
}
2727

2828
@Bean
29-
public CacheManager caffeineCacheManager(Caffeine<Object, Object> caffeine) {
29+
public CacheManager caffeineCacheManager(Caffeine<@NotNull Object, @NotNull Object> caffeine) {
3030
CaffeineCacheManager caffeineCacheManager = new CaffeineCacheManager();
3131
caffeineCacheManager.setCaffeine(caffeine);
3232
caffeineCacheManager.setAsyncCacheMode(true);
@@ -46,7 +46,7 @@ public void registerHints(@NotNull RuntimeHints hints, ClassLoader classLoader)
4646
.reflection()
4747
.registerType(
4848
clazz,
49-
MemberCategory.DECLARED_FIELDS,
49+
MemberCategory.ACCESS_DECLARED_FIELDS,
5050
MemberCategory.INVOKE_DECLARED_METHODS,
5151
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS));
5252
}

src/main/java/li/naska/bgg/configuration/JacksonConfiguration.java

Lines changed: 50 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,72 @@
11
package li.naska.bgg.configuration;
22

3+
import com.fasterxml.jackson.annotation.JsonIgnore;
34
import com.fasterxml.jackson.annotation.JsonInclude.Include;
4-
import com.fasterxml.jackson.databind.DeserializationFeature;
5-
import com.fasterxml.jackson.databind.SerializationFeature;
6-
import com.fasterxml.jackson.databind.module.SimpleModule;
7-
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
85
import jakarta.validation.constraints.NotNull;
6+
import jakarta.xml.bind.JAXBElement;
97
import java.time.LocalDate;
108
import java.time.LocalDateTime;
119
import java.util.Arrays;
1210
import java.util.stream.Stream;
13-
import li.naska.bgg.util.ClasspathUtils;
14-
import li.naska.bgg.util.ReflectionUtils;
15-
import li.naska.bgg.util.SafeLocalDateJacksonDeserializer;
16-
import li.naska.bgg.util.SafeLocalDateTimeJacksonDeserializer;
11+
import li.naska.bgg.util.*;
1712
import org.springframework.aot.hint.MemberCategory;
1813
import org.springframework.aot.hint.RuntimeHints;
1914
import org.springframework.aot.hint.RuntimeHintsRegistrar;
20-
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
15+
import org.springframework.boot.jackson.autoconfigure.JsonMapperBuilderCustomizer;
2116
import org.springframework.context.annotation.Bean;
2217
import org.springframework.context.annotation.Configuration;
2318
import org.springframework.context.annotation.ImportRuntimeHints;
19+
import tools.jackson.databind.DeserializationFeature;
20+
import tools.jackson.databind.cfg.DateTimeFeature;
21+
import tools.jackson.databind.module.SimpleDeserializers;
22+
import tools.jackson.databind.module.SimpleModule;
2423

2524
@Configuration
2625
@ImportRuntimeHints(JacksonConfiguration.JacksonRuntimeHints.class)
2726
public class JacksonConfiguration {
2827

2928
@Bean
30-
public Jackson2ObjectMapperBuilderCustomizer objectMapperBuilderCustomizer() {
31-
return builder -> {
32-
// Use ISO-8601 for dates
33-
builder.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
34-
// see BggUserV4ResponseBody#adminBadges
35-
builder.featuresToEnable(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT);
36-
// set to true to increase strictness
37-
builder.failOnUnknownProperties(false);
38-
builder.postConfigurer(objectMapper -> {
39-
// FIXME https://stackoverflow.com/a/56008395/4074057
40-
objectMapper.setDefaultPropertyInclusion(Include.NON_NULL);
41-
SimpleModule javaTimeModule = new JavaTimeModule();
42-
// deserialize bad formatted dates to null
43-
javaTimeModule.addDeserializer(
44-
LocalDateTime.class, SafeLocalDateTimeJacksonDeserializer.INSTANCE);
45-
// see BggGeekitemV4ResponseBody#commercelinks
46-
javaTimeModule.addDeserializer(LocalDate.class, SafeLocalDateJacksonDeserializer.INSTANCE);
47-
objectMapper.registerModule(javaTimeModule);
48-
});
49-
};
29+
public JsonMapperBuilderCustomizer objectMapperBuilderCustomizer() {
30+
return builder -> builder
31+
// Use ISO-8601 for dates
32+
.disable(DateTimeFeature.WRITE_DATES_AS_TIMESTAMPS)
33+
// see BggUserV4ResponseBody#adminBadges
34+
.enable(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT)
35+
// set to enabled to increase strictness
36+
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
37+
.changeDefaultPropertyInclusion(incl -> incl.withValueInclusion(Include.NON_NULL))
38+
.addModule(new SafeJavaTimeModule())
39+
.addMixIn(JAXBElement.class, JAXBElementMixin.class);
40+
}
41+
42+
interface JAXBElementMixin<T> {
43+
@JsonIgnore
44+
Class<T> getDeclaredType();
45+
46+
@JsonIgnore
47+
Class<?> getScope();
48+
49+
@JsonIgnore
50+
boolean isNil();
51+
52+
@JsonIgnore
53+
boolean isGlobalScope();
54+
55+
@JsonIgnore
56+
boolean isTypeSubstituted();
57+
}
58+
59+
public static class SafeJavaTimeModule extends SimpleModule {
60+
@Override
61+
public void setupModule(SetupContext context) {
62+
SimpleDeserializers deserializers = new SimpleDeserializers();
63+
// see BggGeekitemV4ResponseBody#commercelinks
64+
deserializers.addDeserializer(
65+
LocalDateTime.class, SafeLocalDateTimeJacksonDeserializer.INSTANCE);
66+
// see BggGeekitemV4ResponseBody#commercelinks
67+
deserializers.addDeserializer(LocalDate.class, SafeLocalDateJacksonDeserializer.INSTANCE);
68+
context.addDeserializers(deserializers);
69+
}
5070
}
5171

5272
static class JacksonRuntimeHints implements RuntimeHintsRegistrar {
@@ -66,7 +86,7 @@ public void registerHints(@NotNull RuntimeHints hints, ClassLoader classLoader)
6686
.reflection()
6787
.registerType(
6888
clazz,
69-
MemberCategory.DECLARED_FIELDS,
89+
MemberCategory.ACCESS_DECLARED_FIELDS,
7090
MemberCategory.INVOKE_DECLARED_METHODS,
7191
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS));
7292
}

src/main/java/li/naska/bgg/configuration/JaxbConfiguration.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ public void registerHints(@NotNull RuntimeHints hints, ClassLoader classLoader)
9898
.reflection()
9999
.registerType(
100100
clazz,
101-
MemberCategory.DECLARED_FIELDS,
101+
MemberCategory.ACCESS_DECLARED_FIELDS,
102102
MemberCategory.INVOKE_DECLARED_METHODS,
103103
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS));
104104

src/main/java/li/naska/bgg/configuration/OpenApiConfiguration.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public void registerHints(@NotNull RuntimeHints hints, ClassLoader classLoader)
8080
.reflection()
8181
.registerType(
8282
clazz,
83-
MemberCategory.DECLARED_FIELDS,
83+
MemberCategory.ACCESS_DECLARED_FIELDS,
8484
MemberCategory.INVOKE_DECLARED_METHODS,
8585
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS));
8686
}

src/main/java/li/naska/bgg/configuration/WebClientConfiguration.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package li.naska.bgg.configuration;
22

33
import java.time.Duration;
4-
import org.springframework.boot.web.reactive.function.client.WebClientCustomizer;
4+
import org.springframework.boot.webclient.WebClientCustomizer;
55
import org.springframework.context.annotation.Bean;
66
import org.springframework.context.annotation.Configuration;
77
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
@@ -15,8 +15,7 @@ public class WebClientConfiguration {
1515
public WebClientCustomizer webClientCustomizer() {
1616
return webClientBuilder -> {
1717
// override Netty HttpClient default behaviour (no max idle time) because connections get
18-
// closed
19-
// by BGG after some time
18+
// closed by BGG after some time
2019
ConnectionProvider connectionProvider = ConnectionProvider.builder("customConnectionPool")
2120
.maxIdleTime(Duration.ofMillis(60000))
2221
.maxLifeTime(Duration.ofMinutes(5))

src/main/java/li/naska/bgg/exception/GlobalErrorWebExceptionHandler.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
import java.util.Map;
44
import java.util.Optional;
55
import org.springframework.boot.autoconfigure.web.WebProperties;
6-
import org.springframework.boot.autoconfigure.web.reactive.error.AbstractErrorWebExceptionHandler;
76
import org.springframework.boot.web.error.ErrorAttributeOptions;
8-
import org.springframework.boot.web.reactive.error.ErrorAttributes;
7+
import org.springframework.boot.webflux.autoconfigure.error.AbstractErrorWebExceptionHandler;
8+
import org.springframework.boot.webflux.error.ErrorAttributes;
99
import org.springframework.context.ApplicationContext;
1010
import org.springframework.core.annotation.Order;
1111
import org.springframework.http.MediaType;

src/main/java/li/naska/bgg/repository/BggUsersV4Repository.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package li.naska.bgg.repository;
22

3-
import com.fasterxml.jackson.core.type.TypeReference;
43
import java.nio.charset.StandardCharsets;
54
import java.util.List;
65
import java.util.Optional;
@@ -18,6 +17,7 @@
1817
import org.springframework.web.reactive.function.client.WebClient;
1918
import org.springframework.web.server.ResponseStatusException;
2019
import reactor.core.publisher.Mono;
20+
import tools.jackson.core.type.TypeReference;
2121

2222
@Repository
2323
public class BggUsersV4Repository {

src/main/java/li/naska/bgg/util/JsonProcessor.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
package li.naska.bgg.util;
22

3-
import com.fasterxml.jackson.core.JsonProcessingException;
4-
import com.fasterxml.jackson.core.type.TypeReference;
5-
import com.fasterxml.jackson.databind.ObjectMapper;
63
import com.jayway.jsonpath.JsonPath;
74
import java.util.Optional;
85
import lombok.extern.slf4j.Slf4j;
96
import org.springframework.http.HttpStatus;
107
import org.springframework.stereotype.Component;
118
import org.springframework.web.server.ResponseStatusException;
9+
import tools.jackson.core.JacksonException;
10+
import tools.jackson.core.type.TypeReference;
11+
import tools.jackson.databind.ObjectMapper;
1212

1313
@Component
1414
@Slf4j
@@ -23,7 +23,7 @@ public JsonProcessor(ObjectMapper objectMapper) {
2323
public <T> T toJavaObject(String jsonString, Class<T> clazz) {
2424
try {
2525
return objectMapper.readValue(jsonString, clazz);
26-
} catch (JsonProcessingException e) {
26+
} catch (JacksonException e) {
2727
log.error("Error parsing response body", e);
2828
throw new ResponseStatusException(
2929
HttpStatus.INTERNAL_SERVER_ERROR, "Error parsing server response");
@@ -33,7 +33,7 @@ public <T> T toJavaObject(String jsonString, Class<T> clazz) {
3333
public <T> T toJavaObject(String jsonString, TypeReference<T> typeReference) {
3434
try {
3535
return objectMapper.readValue(jsonString, typeReference);
36-
} catch (JsonProcessingException e) {
36+
} catch (JacksonException e) {
3737
log.error("Error parsing response body", e);
3838
throw new ResponseStatusException(
3939
HttpStatus.INTERNAL_SERVER_ERROR, "Error parsing server response");

src/main/java/li/naska/bgg/util/QueryParameters.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
package li.naska.bgg.util;
22

3-
import com.fasterxml.jackson.core.type.TypeReference;
4-
import com.fasterxml.jackson.databind.ObjectMapper;
53
import java.util.Map;
64
import lombok.experimental.UtilityClass;
75
import org.springframework.util.LinkedMultiValueMap;
86
import org.springframework.util.MultiValueMap;
7+
import tools.jackson.core.type.TypeReference;
8+
import tools.jackson.databind.ObjectMapper;
99

1010
@UtilityClass
1111
public class QueryParameters {

0 commit comments

Comments
 (0)