Skip to content

Commit 0324d63

Browse files
Add compatibility for Spring Boot 3.X.X (Jakarta / Kafka upgrade) (#138)
* FEAT: Spring Boot 2 & 3 compatibility * FIX: InvokeUnchecked for Kafka send to dispatch raw exception instead of InvocationException --------- Co-authored-by: brian-mulier <[email protected]>
1 parent d809e3b commit 0324d63

File tree

17 files changed

+147
-61
lines changed

17 files changed

+147
-61
lines changed

.github/workflows/build.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ jobs:
2929
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
3030
restore-keys: |
3131
${{ runner.os }}-maven-
32-
3332
- name: Build
3433
run: mvn -B verify
3534

mockfaster/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@
129129
<dependency>
130130
<groupId>io.rest-assured</groupId>
131131
<artifactId>rest-assured</artifactId>
132-
<version>3.3.0</version>
132+
<version>5.3.0</version>
133133
<scope>test</scope>
134134
</dependency>
135135
<dependency>

pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,15 +71,15 @@
7171
<dependency>
7272
<groupId>org.springframework.cloud</groupId>
7373
<artifactId>spring-cloud-dependencies</artifactId>
74-
<version>2021.0.0</version>
74+
<version>2022.0.1</version>
7575
<type>pom</type>
7676
<scope>import</scope>
7777
</dependency>
7878
<dependency>
7979
<!-- Import dependency management from Spring Boot -->
8080
<groupId>org.springframework.boot</groupId>
8181
<artifactId>spring-boot-dependencies</artifactId>
82-
<version>2.6.2</version>
82+
<version>3.0.2</version>
8383
<type>pom</type>
8484
<scope>import</scope>
8585
</dependency>

tzatziki-spring-jpa/pom.xml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@
3636
<groupId>org.springframework</groupId>
3737
<artifactId>spring-jdbc</artifactId>
3838
</dependency>
39+
<dependency>
40+
<groupId>com.fasterxml.jackson.datatype</groupId>
41+
<artifactId>jackson-datatype-hibernate5-jakarta</artifactId>
42+
</dependency>
3943
<dependency>
4044
<groupId>com.fasterxml.jackson.datatype</groupId>
4145
<artifactId>jackson-datatype-hibernate5</artifactId>
@@ -54,7 +58,7 @@
5458
<dependency>
5559
<groupId>org.flywaydb</groupId>
5660
<artifactId>flyway-core</artifactId>
57-
<version>6.4.4</version>
61+
<version>9.12.0</version>
5862
<scope>test</scope>
5963
</dependency>
6064
<dependency>

tzatziki-spring-jpa/src/main/java/com/decathlon/tzatziki/steps/SpringJPASteps.java

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
11
package com.decathlon.tzatziki.steps;
22

33
import com.decathlon.tzatziki.utils.*;
4-
import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module;
54
import io.cucumber.java.Before;
65
import io.cucumber.java.en.Given;
76
import io.cucumber.java.en.Then;
87
import org.apache.commons.lang3.reflect.TypeUtils;
8+
import org.burningwave.core.classes.Modules;
99
import org.jetbrains.annotations.NotNull;
1010
import org.jetbrains.annotations.Nullable;
1111
import org.springframework.beans.factory.annotation.Autowired;
12+
import org.springframework.core.annotation.AnnotationUtils;
1213
import org.springframework.data.domain.Sort;
1314
import org.springframework.data.repository.CrudRepository;
1415
import org.springframework.data.repository.PagingAndSortingRepository;
1516
import org.springframework.jdbc.core.JdbcTemplate;
1617
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
1718

18-
import javax.persistence.Table;
1919
import javax.sql.DataSource;
20+
import java.lang.annotation.Annotation;
21+
import java.lang.reflect.Proxy;
2022
import java.lang.reflect.Type;
2123
import java.lang.reflect.TypeVariable;
2224
import java.util.Arrays;
@@ -41,7 +43,6 @@ public class SpringJPASteps {
4143
static {
4244
DynamicTransformers.register(Type.class, TypeParser::parse);
4345
DynamicTransformers.register(InsertionMode.class, InsertionMode::parse);
44-
JacksonMapper.with(objectMapper -> objectMapper.registerModule(new Hibernate5Module()));
4546
}
4647

4748
public static boolean autoclean = true;
@@ -56,6 +57,10 @@ public class SpringJPASteps {
5657
private final ObjectSteps objects;
5758
private final SpringSteps spring;
5859

60+
static {
61+
JacksonMapper.with(objectMapper -> objectMapper.registerModule(PersistenceUtil.getMapperModule()));
62+
}
63+
5964
public SpringJPASteps(ObjectSteps objects, SpringSteps spring) {
6065
this.objects = objects;
6166
this.spring = spring;
@@ -106,13 +111,19 @@ public void before() {
106111
return c2.getPackageName().startsWith(TypeParser.defaultPackage) ? 1 : 0;
107112
})
108113
.<Map.Entry<String, Class<?>>>mapMulti((clazz, consumer) -> {
109-
String tableName = Optional.ofNullable(clazz.getAnnotation(Table.class)).map(Table::name)
110-
.orElse(Optional.ofNullable(clazz.getAnnotation(org.springframework.data.relational.core.mapping.Table.class)).map(org.springframework.data.relational.core.mapping.Table::value).orElse(null));
114+
String tableName = getTableName(clazz);
111115
if (tableName != null) consumer.accept(Map.entry(tableName, clazz));
112116
}).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (t1, t2) -> t1));
113117
}
114118
}
115119

120+
@Nullable
121+
private String getTableName(Class<?> clazz) {
122+
return Optional.ofNullable(clazz.getAnnotation(PersistenceUtil.<Annotation>getPersistenceClass("Table")))
123+
.map(tableAnnotation -> (String) AnnotationUtils.getValue(tableAnnotation, "name"))
124+
.orElse(Optional.ofNullable(clazz.getAnnotation(org.springframework.data.relational.core.mapping.Table.class)).map(org.springframework.data.relational.core.mapping.Table::value).orElse(null));
125+
}
126+
116127
@NotNull
117128
private Stream<DataSource> dataSources() {
118129
if (entityManagerFactories != null) {
@@ -219,7 +230,7 @@ public <E> void the_repository_will_contain_with_type(Guard guard, CrudRepositor
219230
dataSources().forEach(dataSource -> DatabaseCleaner.setTriggers(dataSource, schemaToClean, DatabaseCleaner.TriggerStatus.disable));
220231
}
221232
if (insertionMode == InsertionMode.ONLY) {
222-
String table = entityClass.getAnnotation(Table.class).name();
233+
String table = getTableName(entityClass);
223234
DataSource dataSource = entityManagerFactories.stream()
224235
.filter(entityManagerFactory -> entityManagerFactory.getPersistenceUnitInfo() != null)
225236
.filter(entityManagerFactory -> entityManagerFactory.getPersistenceUnitInfo().getManagedClassNames().contains(entityClass.getName()))
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package com.decathlon.tzatziki.utils;
2+
3+
import com.fasterxml.jackson.databind.Module;
4+
import edu.emory.mathcs.backport.java.util.Collections;
5+
import lombok.AccessLevel;
6+
import lombok.AllArgsConstructor;
7+
8+
import java.util.HashMap;
9+
import java.util.Map;
10+
11+
import static com.decathlon.tzatziki.utils.Unchecked.unchecked;
12+
13+
@SuppressWarnings("unchecked")
14+
@AllArgsConstructor(access = AccessLevel.PRIVATE)
15+
public class PersistenceUtil {
16+
private static final Map<String, Class<?>> persistenceClassByName = Collections.synchronizedMap(new HashMap<>());
17+
18+
public static Module getMapperModule() {
19+
Class<?> tableClass = getPersistenceClass("Table");
20+
Class<Module> mapperModuleClass;
21+
22+
if (tableClass.getPackageName().equals("javax.persistence"))
23+
mapperModuleClass = unchecked(() -> (Class<Module>) Class.forName("com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module"));
24+
else
25+
mapperModuleClass = unchecked(() -> (Class<Module>) Class.forName("com.fasterxml.jackson.datatype.hibernate5.jakarta.Hibernate5JakartaModule"));
26+
27+
return unchecked(() -> mapperModuleClass.getConstructor().newInstance());
28+
}
29+
30+
public static <T> Class<T> getPersistenceClass(String className) {
31+
return (Class<T>) persistenceClassByName.computeIfAbsent(
32+
className,
33+
clazz -> {
34+
Class<Object> foundClass;
35+
try {
36+
foundClass = (Class<Object>) Class.forName("javax.persistence." + className);
37+
} catch (ClassNotFoundException e) {
38+
foundClass = unchecked(() -> (Class<Object>) Class.forName("jakarta.persistence." + className));
39+
}
40+
return foundClass;
41+
}
42+
);
43+
}
44+
45+
}

tzatziki-spring-jpa/src/test/java/com/another_org/CorruptedEvilness.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
package com.another_org;
22

3+
import jakarta.persistence.Column;
4+
import jakarta.persistence.Entity;
5+
import jakarta.persistence.GeneratedValue;
6+
import jakarta.persistence.GenerationType;
7+
import jakarta.persistence.Id;
8+
import jakarta.persistence.Table;
39
import lombok.Getter;
410
import lombok.NoArgsConstructor;
511

6-
import javax.persistence.*;
7-
812
@NoArgsConstructor
913
@Getter
1014
@Entity

tzatziki-spring-jpa/src/test/java/com/decathlon/tzatziki/app/TestApplication.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import org.springframework.boot.autoconfigure.domain.EntityScan;
66
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
77

8-
@SpringBootApplication
8+
@SpringBootApplication(scanBasePackages = "com.decathlon.tzatziki")
99
@EnableJpaRepositories(basePackages = {"com.another_org", "com.decathlon.tzatziki.app"})
1010
@EntityScan(basePackages = {"com.another_org", "com.decathlon.tzatziki.app"})
1111
public class TestApplication {

tzatziki-spring-jpa/src/test/java/com/decathlon/tzatziki/app/entity_listeners/SuperUserEntityListener.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import com.decathlon.tzatziki.app.model.SuperUser;
44

5-
import javax.persistence.PrePersist;
5+
import jakarta.persistence.PrePersist;
66

77
public class SuperUserEntityListener {
88
@PrePersist

tzatziki-spring-jpa/src/test/java/com/decathlon/tzatziki/app/model/Evilness.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
package com.decathlon.tzatziki.app.model;
22

3+
import jakarta.persistence.Column;
4+
import jakarta.persistence.Entity;
5+
import jakarta.persistence.GeneratedValue;
6+
import jakarta.persistence.GenerationType;
7+
import jakarta.persistence.Id;
8+
import jakarta.persistence.Table;
39
import lombok.Getter;
410
import lombok.NoArgsConstructor;
511

6-
import javax.persistence.*;
7-
import java.time.Instant;
8-
912
@NoArgsConstructor
1013
@Getter
1114
@Entity

0 commit comments

Comments
 (0)