Skip to content

Commit 0c9c329

Browse files
authored
[FSSDK-11986] upgrade Jackson serializer deprecated class (#587)
1 parent ade5a4d commit 0c9c329

File tree

5 files changed

+67
-17
lines changed

5 files changed

+67
-17
lines changed

.github/workflows/java.yml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,17 +49,18 @@ jobs:
4949
strategy:
5050
fail-fast: false
5151
matrix:
52-
jdk: [8, 9]
52+
# github not support JVM 8 anymore
53+
jdk: [11, 17]
5354
optimizely_default_parser: [GSON_CONFIG_PARSER, JACKSON_CONFIG_PARSER, JSON_CONFIG_PARSER, JSON_SIMPLE_CONFIG_PARSER]
5455
steps:
5556
- name: checkout
5657
uses: actions/checkout@v4
5758

5859
- name: set up JDK ${{ matrix.jdk }}
59-
uses: AdoptOpenJDK/install-jdk@v1
60+
uses: actions/setup-java@v4
6061
with:
61-
version: ${{ matrix.jdk }}
62-
architecture: x64
62+
java-version: ${{ matrix.jdk }}
63+
distribution: 'temurin'
6364

6465
- name: Grant execute permission for gradlew
6566
run: chmod +x gradlew

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@ dependencies {
4444
compile 'com.optimizely.ab:core-api:{VERSION}'
4545
compile 'com.optimizely.ab:core-httpclient-impl:{VERSION}'
4646
// The SDK integrates with multiple JSON parsers, here we use Jackson.
47-
compile 'com.fasterxml.jackson.core:jackson-core:2.7.1'
48-
compile 'com.fasterxml.jackson.core:jackson-annotations:2.7.1'
49-
compile 'com.fasterxml.jackson.core:jackson-databind:2.7.1'
47+
compile 'com.fasterxml.jackson.core:jackson-core:2.13.5'
48+
compile 'com.fasterxml.jackson.core:jackson-annotations:2.13.5'
49+
compile 'com.fasterxml.jackson.core:jackson-databind:2.13.5'
5050
}
5151
```
5252

core-api/src/main/java/com/optimizely/ab/event/internal/serializer/JacksonSerializer.java

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
22
*
3-
* Copyright 2016-2017, 2019, Optimizely and contributors
3+
* Copyright 2016-2017, 2019, 2025 Optimizely and contributors
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
66
* you may not use this file except in compliance with the License.
@@ -19,13 +19,41 @@
1919
import com.fasterxml.jackson.annotation.JsonInclude;
2020
import com.fasterxml.jackson.core.JsonProcessingException;
2121
import com.fasterxml.jackson.databind.ObjectMapper;
22-
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
2322

2423
class JacksonSerializer implements Serializer {
2524

26-
private ObjectMapper mapper =
27-
new ObjectMapper().setPropertyNamingStrategy(
28-
PropertyNamingStrategy.SNAKE_CASE);
25+
private ObjectMapper mapper = createMapper();
26+
27+
/**
28+
* Creates an ObjectMapper with snake_case naming strategy.
29+
* Supports both Jackson 2.12+ (PropertyNamingStrategies) and earlier versions (PropertyNamingStrategy).
30+
* Uses reflection to avoid compile-time dependencies on either API.
31+
*/
32+
static ObjectMapper createMapper() {
33+
ObjectMapper objectMapper = new ObjectMapper();
34+
Object namingStrategy = getSnakeCaseStrategy();
35+
objectMapper.setPropertyNamingStrategy((com.fasterxml.jackson.databind.PropertyNamingStrategy) namingStrategy);
36+
return objectMapper;
37+
}
38+
39+
/**
40+
* Gets the snake case naming strategy, supporting both Jackson 2.12+ and earlier versions.
41+
*/
42+
private static Object getSnakeCaseStrategy() {
43+
try {
44+
// Try Jackson 2.12+ API first
45+
Class<?> strategiesClass = Class.forName("com.fasterxml.jackson.databind.PropertyNamingStrategies");
46+
return strategiesClass.getField("SNAKE_CASE").get(null);
47+
} catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) {
48+
try {
49+
// Fall back to Jackson 2.11 and earlier (deprecated but compatible)
50+
Class<?> strategyClass = Class.forName("com.fasterxml.jackson.databind.PropertyNamingStrategy");
51+
return strategyClass.getField("SNAKE_CASE").get(null);
52+
} catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException ex) {
53+
throw new RuntimeException("Unable to find snake_case naming strategy in Jackson", ex);
54+
}
55+
}
56+
}
2957

3058
public <T> String serialize(T payload) {
3159
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

core-api/src/test/java/com/optimizely/ab/event/internal/serializer/JacksonSerializerTest.java

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
import com.fasterxml.jackson.databind.ObjectMapper;
2020

21-
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
2221
import com.optimizely.ab.event.internal.payload.*;
2322

2423
import org.junit.Test;
@@ -41,10 +40,28 @@
4140
public class JacksonSerializerTest {
4241

4342
private JacksonSerializer serializer = new JacksonSerializer();
44-
private ObjectMapper mapper =
45-
new ObjectMapper().setPropertyNamingStrategy(
46-
PropertyNamingStrategy.SNAKE_CASE);
43+
private ObjectMapper mapper = JacksonSerializer.createMapper();
4744

45+
@Test
46+
public void createMapperSucceeds() {
47+
// Verify that createMapper() successfully creates an ObjectMapper with snake_case naming
48+
// This tests that the reflection logic works for the current Jackson version
49+
ObjectMapper testMapper = JacksonSerializer.createMapper();
50+
assertNotNull("Mapper should be created successfully", testMapper);
51+
52+
// Verify snake_case naming by serializing a simple object
53+
class TestObject {
54+
@SuppressWarnings("unused")
55+
public String getMyFieldName() { return "test"; }
56+
}
57+
58+
try {
59+
String json = testMapper.writeValueAsString(new TestObject());
60+
assertTrue("Should use snake_case naming", json.contains("my_field_name"));
61+
} catch (Exception e) {
62+
throw new RuntimeException("Failed to serialize with snake_case naming", e);
63+
}
64+
}
4865

4966
@Test
5067
public void serializeImpression() throws IOException {

java-quickstart/build.gradle

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ dependencies {
44
implementation project(':core-api')
55
implementation project(':core-httpclient-impl')
66

7-
implementation group: 'com.google.code.gson', name: 'gson', version: gsonVersion
7+
// implementation group: 'com.google.code.gson', name: 'gson', version: gsonVersion
8+
implementation 'com.fasterxml.jackson.core:jackson-core:2.17.0'
9+
implementation 'com.fasterxml.jackson.core:jackson-annotations:2.17.0'
10+
implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.0'
11+
812
implementation group: 'org.apache.httpcomponents', name: 'httpclient', version: httpClientVersion
913
implementation group: 'org.apache.logging.log4j', name: 'log4j-api', version: log4jVersion
1014
implementation group: 'org.apache.logging.log4j', name: 'log4j-core', version: log4jVersion

0 commit comments

Comments
 (0)