Skip to content

Commit c4d79b3

Browse files
[BUG-8620] Make DefaultJsonSerializer resilient to serializer init failures
Wrap each serializer instantiation in try-catch so that if one library's initialization fails (e.g., Jackson's PropertyNamingStrategies fields obfuscated by R8), the factory falls through to the next available JSON library instead of crashing with NoClassDefFoundError. Also add DefaultJsonSerializer unit tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 5752354 commit c4d79b3

2 files changed

Lines changed: 81 additions & 14 deletions

File tree

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

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -47,23 +47,45 @@ public static Serializer getInstance() {
4747
*/
4848
private static @Nonnull
4949
Serializer create() {
50-
Serializer serializer;
51-
5250
if (isPresent("com.fasterxml.jackson.databind.ObjectMapper")) {
53-
serializer = new JacksonSerializer();
54-
} else if (isPresent("com.google.gson.Gson")) {
55-
serializer = new GsonSerializer();
56-
} else if (isPresent("org.json.simple.JSONObject")) {
57-
serializer = new JsonSimpleSerializer();
58-
} else if (isPresent("org.json.JSONObject")) {
59-
serializer = new JsonSerializer();
60-
} else {
61-
throw new MissingJsonParserException("unable to locate a JSON parser. "
62-
+ "Please see <link> for more information");
51+
try {
52+
Serializer serializer = new JacksonSerializer();
53+
logger.debug("using json serializer: {}", serializer.getClass().getSimpleName());
54+
return serializer;
55+
} catch (Throwable t) {
56+
logger.warn("Jackson found on classpath but serializer initialization failed, trying next option.", t);
57+
}
58+
}
59+
if (isPresent("com.google.gson.Gson")) {
60+
try {
61+
Serializer serializer = new GsonSerializer();
62+
logger.debug("using json serializer: {}", serializer.getClass().getSimpleName());
63+
return serializer;
64+
} catch (Throwable t) {
65+
logger.warn("Gson found on classpath but serializer initialization failed, trying next option.", t);
66+
}
67+
}
68+
if (isPresent("org.json.simple.JSONObject")) {
69+
try {
70+
Serializer serializer = new JsonSimpleSerializer();
71+
logger.debug("using json serializer: {}", serializer.getClass().getSimpleName());
72+
return serializer;
73+
} catch (Throwable t) {
74+
logger.warn("json-simple found on classpath but serializer initialization failed, trying next option.", t);
75+
}
76+
}
77+
if (isPresent("org.json.JSONObject")) {
78+
try {
79+
Serializer serializer = new JsonSerializer();
80+
logger.debug("using json serializer: {}", serializer.getClass().getSimpleName());
81+
return serializer;
82+
} catch (Throwable t) {
83+
logger.warn("org.json found on classpath but serializer initialization failed.", t);
84+
}
6385
}
6486

65-
logger.debug("using json serializer: {}", serializer.getClass().getSimpleName());
66-
return serializer;
87+
throw new MissingJsonParserException("unable to locate a JSON parser. "
88+
+ "Please see <link> for more information");
6789
}
6890

6991
private static boolean isPresent(@Nonnull String className) {
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/**
2+
*
3+
* Copyright 2026, Optimizely and contributors
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package com.optimizely.ab.event.internal.serializer;
18+
19+
import org.junit.Test;
20+
import static org.junit.Assert.*;
21+
22+
public class DefaultJsonSerializerTest {
23+
24+
@Test
25+
public void getInstanceReturnsNonNull() {
26+
Serializer serializer = DefaultJsonSerializer.getInstance();
27+
assertNotNull("getInstance() should return a non-null serializer", serializer);
28+
}
29+
30+
@Test
31+
public void getInstanceReturnsSameInstance() {
32+
Serializer first = DefaultJsonSerializer.getInstance();
33+
Serializer second = DefaultJsonSerializer.getInstance();
34+
assertSame("getInstance() should return the same singleton instance", first, second);
35+
}
36+
37+
@Test
38+
public void instanceCanSerialize() {
39+
Serializer serializer = DefaultJsonSerializer.getInstance();
40+
String result = serializer.serialize(java.util.Collections.singletonMap("test_key", "test_value"));
41+
assertNotNull("Serializer should produce non-null output", result);
42+
assertTrue("Serialized output should contain the key", result.contains("test_key"));
43+
assertTrue("Serialized output should contain the value", result.contains("test_value"));
44+
}
45+
}

0 commit comments

Comments
 (0)