From a1646219eb4fab3cd813dfe77a49155670b0d643 Mon Sep 17 00:00:00 2001 From: vincerevu <118267358+vincerevu@users.noreply.github.com> Date: Fri, 10 Apr 2026 20:27:54 +0000 Subject: [PATCH 1/2] Optimize jsonMapper instantiation Cache the Jackson JsonMapper instance in a lazy val to avoid the massive performance overhead of registering modules and building the mapper on every single invocation. This single lazily-initialized instance is thread-safe and can be reused globally. --- .jules/bolt.md | 4 ++++ .../src/main/kotlin/com/openai/core/ObjectMappers.kt | 8 +++++++- 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 .jules/bolt.md diff --git a/.jules/bolt.md b/.jules/bolt.md new file mode 100644 index 00000000..a2cc1ad7 --- /dev/null +++ b/.jules/bolt.md @@ -0,0 +1,4 @@ +## 2024-04-10 - Optimizing jsonMapper() creation +**Learning:** `jsonMapper()` is a global function in `com.openai.core.ObjectMappers` that calls `JsonMapper.builder()...build()` every time it's invoked. This is a very expensive operation in Jackson, as module registration and builder construction are slow. This method is called in many places like parsing exceptions, initializing clients, tests, and webhooks. Jackson documentation recommends configuring `ObjectMapper` (or `JsonMapper`) once and reusing it. + +**Action:** Convert `jsonMapper()` to return a single lazily-initialized or statically-initialized `JsonMapper` instance. Or, change it to a lazy property like `val jsonMapper: JsonMapper by lazy { ... }` (but since it's an API, keep `fun jsonMapper(): JsonMapper` and back it with a private constant). diff --git a/openai-java-core/src/main/kotlin/com/openai/core/ObjectMappers.kt b/openai-java-core/src/main/kotlin/com/openai/core/ObjectMappers.kt index a552585e..2b61bf03 100644 --- a/openai-java-core/src/main/kotlin/com/openai/core/ObjectMappers.kt +++ b/openai-java-core/src/main/kotlin/com/openai/core/ObjectMappers.kt @@ -29,7 +29,10 @@ import java.time.ZoneId import java.time.format.DateTimeFormatter import java.time.temporal.ChronoField -fun jsonMapper(): JsonMapper = +// Cache the Jackson JsonMapper instance to avoid the massive performance overhead of +// registering modules and building the mapper on every single invocation. +// This single lazily-initialized instance is thread-safe and can be reused globally. +private val JSON_MAPPER: JsonMapper by lazy { JsonMapper.builder() .addModule(kotlinModule()) .addModule(Jdk8Module()) @@ -112,6 +115,9 @@ fun jsonMapper(): JsonMapper = .disable(MapperFeature.AUTO_DETECT_IS_GETTERS) .disable(MapperFeature.AUTO_DETECT_SETTERS) .build() +} + +fun jsonMapper(): JsonMapper = JSON_MAPPER /** A serializer that serializes [InputStream] to bytes. */ private object InputStreamSerializer : BaseSerializer(InputStream::class) { From 35fe9eede6c2078306cbad9d1fa5d5070c5e3425 Mon Sep 17 00:00:00 2001 From: vincerevu <118267358+vincerevu@users.noreply.github.com> Date: Sat, 11 Apr 2026 02:20:23 +0000 Subject: [PATCH 2/2] Optimize jsonMapper instantiation Cache the Jackson JsonMapper instance in a lazy val to avoid the massive performance overhead of registering modules and building the mapper on every single invocation. This single lazily-initialized instance is thread-safe and can be reused globally. --- .jules/bolt.md | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 .jules/bolt.md diff --git a/.jules/bolt.md b/.jules/bolt.md deleted file mode 100644 index a2cc1ad7..00000000 --- a/.jules/bolt.md +++ /dev/null @@ -1,4 +0,0 @@ -## 2024-04-10 - Optimizing jsonMapper() creation -**Learning:** `jsonMapper()` is a global function in `com.openai.core.ObjectMappers` that calls `JsonMapper.builder()...build()` every time it's invoked. This is a very expensive operation in Jackson, as module registration and builder construction are slow. This method is called in many places like parsing exceptions, initializing clients, tests, and webhooks. Jackson documentation recommends configuring `ObjectMapper` (or `JsonMapper`) once and reusing it. - -**Action:** Convert `jsonMapper()` to return a single lazily-initialized or statically-initialized `JsonMapper` instance. Or, change it to a lazy property like `val jsonMapper: JsonMapper by lazy { ... }` (but since it's an API, keep `fun jsonMapper(): JsonMapper` and back it with a private constant).