Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
bd58126
testing jackson blackbird for json serialization performance
wezell Aug 21, 2025
be7daf1
fixing test
wezell Oct 2, 2025
bc8c122
Merge branch 'main' into objectmaper-blackbird
wezell Oct 7, 2025
bc4c989
feat(perf): implement jackson-blackbird for memory and cpu savings wh…
wezell Oct 7, 2025
22eefa3
Merge branch 'main' into issue-33488-objectmaper-blackbird
wezell Oct 7, 2025
d73dd21
Merge branch 'main' into issue-33488-objectmaper-blackbird
wezell Oct 21, 2025
4ff90a3
feat(json-perf): Making sure the ObjectMapper we use is a singleton s…
wezell Oct 21, 2025
66c6c0e
Merge branch 'main' into issue-33488-objectmaper-blackbird
wezell Oct 21, 2025
e8bf820
feat(json-perf): Making sure the ObjectMapper we use is a singleton s…
wezell Oct 21, 2025
d0cc6b8
feat(json-perf): Making sure the ObjectMapper we use is a singleton s…
wezell Oct 22, 2025
5335b7e
feat(json-perf): Making sure the ObjectMapper we use is a singleton s…
wezell Oct 22, 2025
49468cb
feat(json-perf): Making sure the ObjectMapper we use is a singleton s…
wezell Oct 22, 2025
3bb1593
Merge remote-tracking branch 'origin/main' into issue-33488-objectmap…
wezell Oct 27, 2025
d9c479b
feat(json-perf): Making sure the ObjectMapper we use is a singleton s…
wezell Oct 28, 2025
b0d6cbc
feat(json-perf): Making sure the ObjectMapper we use is a singleton s…
wezell Oct 28, 2025
f36f6c3
feat(json-perf): Making sure the ObjectMapper we use is a singleton s…
wezell Oct 28, 2025
0d5947f
feat(json-perf): Making sure the ObjectMapper we use is a singleton s…
wezell Oct 28, 2025
7cb029b
feat(json-perf): Making sure the ObjectMapper we use is a singleton s…
wezell Oct 28, 2025
03f23ad
feat(json-perf): Making sure the ObjectMapper we use is a singleton s…
wezell Oct 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions bom/application/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -970,6 +970,14 @@
<version>2.2</version>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-blackbird</artifactId>
<version>${jackson.version}</version>
</dependency>



<dependency>
<groupId>com.github.jonpeterson</groupId>
<artifactId>jackson-module-model-versioning</artifactId>
Expand Down
4 changes: 4 additions & 0 deletions dotCMS/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -852,6 +852,10 @@
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-parameter-names</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-blackbird</artifactId>
</dependency>

<dependency>
<groupId>com.github.jonpeterson</groupId>
Expand Down
12 changes: 2 additions & 10 deletions dotCMS/src/main/java/com/dotcms/ai/Marshaller.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package com.dotcms.ai;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.dotcms.rest.api.v1.DotObjectMapperProvider;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
Expand Down Expand Up @@ -33,11 +30,6 @@ public static <T> T unmarshal(String input, Class<T> type) throws IOException {
}

private static ObjectMapper createObjectMapper() {
ObjectMapper objectMapper = new ObjectMapper()
.findAndRegisterModules()
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
objectMapper.registerModule(new JavaTimeModule());
return objectMapper;
return DotObjectMapperProvider.getInstance().getIso8610ObjectMapper();
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
package com.dotcms.content.business.json;

import com.dotcms.content.model.Contentlet;
import com.dotcms.rest.api.v1.DotObjectMapperProvider;
import com.dotmarketing.util.Logger;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.guava.GuavaModule;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.github.jonpeterson.jackson.module.versioning.VersioningModule;
import io.vavr.Lazy;
import io.vavr.control.Try;
import java.io.BufferedInputStream;
Expand All @@ -30,15 +26,8 @@ public class ContentletJsonHelper {
/**
* Jackson mapper configuration and lazy initialized instance.
*/
private final Lazy<ObjectMapper> objectMapper = Lazy.of(() -> {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
objectMapper.registerModule(new Jdk8Module());
objectMapper.registerModule(new GuavaModule());
objectMapper.registerModule(new JavaTimeModule());
objectMapper.registerModule(new VersioningModule());
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
return objectMapper;
private static final Lazy<ObjectMapper> objectMapper = Lazy.of(() -> {
return DotObjectMapperProvider.getInstance().getIso8610ObjectMapper();
});

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public class ContentletIndexAPIImpl implements ContentletIndexAPI {
private static final ESIndexAPI esIndexApi = new ESIndexAPI();
private static final ESMappingAPIImpl mappingAPI = new ESMappingAPIImpl();

private static ObjectMapper objectMapper = DotObjectMapperProvider.createDefaultMapper();
private static ObjectMapper objectMapper = DotObjectMapperProvider.getInstance().getDefaultObjectMapper();

public ContentletIndexAPIImpl() {
queueApi = APILocator.getReindexQueueAPI();
Expand Down
12 changes: 6 additions & 6 deletions dotCMS/src/main/java/com/dotcms/dotpubsub/DotPubSubEvent.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.dotcms.dotpubsub;

import com.dotcms.rest.api.v1.DotObjectMapperProvider;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
Expand All @@ -23,15 +24,14 @@ public final class DotPubSubEvent implements Serializable {

// cannot use DotObjectMapperProvider.getInstance().getDefaultObjectMapper() b/c it does not work in
// unit tests
private final static ObjectMapper objectMapper = new ObjectMapper();

private final static Lazy<ObjectMapper> objectMapper = Lazy.of(()->DotObjectMapperProvider.getInstance().getDefaultObjectMapper());
/**
* Construct a DotPubSubEvent from a Json String
*
* @param payloadJson
*/
public DotPubSubEvent(String payloadJson) {
this(Try.of(() -> objectMapper.readValue(payloadJson, Map.class)).getOrElseThrow(e -> {
this(Try.of(() -> objectMapper.get().readValue(payloadJson, Map.class)).getOrElseThrow(e -> {
throw new DotRuntimeException(e);
}));

Expand All @@ -49,7 +49,7 @@ private DotPubSubEvent(Builder builder) {
/**
* Construct an DotPubSubEvent from a map
*
* @param payloadJson
* @param map
*/
public DotPubSubEvent(Map<String, Serializable> map) {

Expand Down Expand Up @@ -109,7 +109,7 @@ public String getTopic() {
private final Lazy<String> payloadAsString = Lazy.of(() -> {
final Map<String, Serializable> payload = getPayload();
try {
return objectMapper.writeValueAsString(payload);
return objectMapper.get().writeValueAsString(payload);
} catch (Exception e) {
Logger.warn(this.getClass(), "unable to write payload as String:" + e.getMessage() + " " + payload);
return null;
Expand Down Expand Up @@ -177,7 +177,7 @@ public Builder(final DotPubSubEvent dotPubSubEvent) {

public Builder withPayload(String payloadJson) {
HashMap<String, Serializable> map =
Try.of(() -> objectMapper.readValue(payloadJson, HashMap.class)).getOrElseThrow(e -> {
Try.of(() -> objectMapper.get().readValue(payloadJson, HashMap.class)).getOrElseThrow(e -> {
throw new DotRuntimeException(e);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,14 @@
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;

public class GoalsDeserializer extends JsonDeserializer<Goals> {

private static ObjectMapper objectMapper = DotObjectMapperProvider.createDefaultMapper();
private static ObjectMapper objectMapper = DotObjectMapperProvider.getInstance().getDefaultObjectMapper();

@Override
public Goals deserialize(JsonParser jsonParser, DeserializationContext ctxt)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;

import java.io.IOException;
import java.util.Map;

Expand All @@ -15,7 +14,7 @@
*/
public class GoalsSerializer extends JsonSerializer<Goals> {

private static ObjectMapper objectMapper = DotObjectMapperProvider.createDefaultMapper();
private static ObjectMapper objectMapper = DotObjectMapperProvider.getInstance().getDefaultObjectMapper();

@Override
public void serialize(final Goals value, final JsonGenerator gen, SerializerProvider serializers)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
package com.dotcms.graphql;

import static com.dotcms.graphql.GraphQLCache.GRAPHQL_CACHE_RESULTS_CONFIG_PROPERTY;
import static com.dotcms.util.HttpRequestDataUtil.getHeaderCaseInsensitive;
import static com.dotcms.util.HttpRequestDataUtil.getParamCaseInsensitive;

import com.dotcms.enterprise.license.LicenseManager;
import com.dotcms.filters.interceptor.Result;
import com.dotcms.filters.interceptor.WebInterceptor;
import com.dotcms.mock.request.DotCMSMockRequest;
import com.dotcms.mock.request.HttpRequestReaderWrapper;
import com.dotcms.mock.response.MockHttpWriterCaptureResponse;
import com.dotcms.rest.api.v1.DotObjectMapperProvider;
import com.dotmarketing.business.CacheLocator;
import com.dotmarketing.util.Config;
import com.dotmarketing.util.UtilMethods;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableMap;
import io.vavr.Lazy;
import io.vavr.control.Try;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Map;
import java.util.Optional;

import static com.dotcms.graphql.GraphQLCache.GRAPHQL_CACHE_RESULTS_CONFIG_PROPERTY;
import static com.dotcms.util.HttpRequestDataUtil.getHeaderCaseInsensitive;
import static com.dotcms.util.HttpRequestDataUtil.getParamCaseInsensitive;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* This interceptor returns the response for a GraphQL request from cache, if available.
Expand Down Expand Up @@ -179,6 +179,10 @@ private Optional<Integer> getCacheTTL(HttpServletRequest requestIn) {
return Optional.of(defaultTTL.get());
}

ObjectMapper getObjectMapper(){
return DotObjectMapperProvider.getInstance().getIso8610ObjectMapper();
}

@Override
public boolean afterIntercept(final HttpServletRequest request,
final HttpServletResponse response) {
Expand All @@ -190,7 +194,7 @@ public boolean afterIntercept(final HttpServletRequest request,
response.setHeader("x-graphql-cache", "miss, writing to cache");
final String graphqlResponse = mockResponse.writer.toString();

final Map<String,Object> map = Try.of(()->new ObjectMapper()
final Map<String,Object> map = Try.of(()->getObjectMapper()
.readValue(graphqlResponse, Map.class)).getOrNull();

Try.run(() -> mockResponse.originalResponse.getWriter().write(graphqlResponse));
Expand Down
15 changes: 2 additions & 13 deletions dotCMS/src/main/java/com/dotcms/jobs/business/util/JobUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.dotcms.mock.request.FakeHttpRequest;
import com.dotcms.mock.request.MockHeaderRequest;
import com.dotcms.mock.request.MockSessionRequest;
import com.dotcms.rest.api.v1.DotObjectMapperProvider;
import com.dotcms.rest.api.v1.temp.DotTempFile;
import com.dotcms.rest.api.v1.temp.TempFileAPI;
import com.dotmarketing.business.APILocator;
Expand All @@ -16,11 +17,6 @@
import com.dotmarketing.util.WebKeys;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.guava.GuavaModule;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.github.jonpeterson.jackson.module.versioning.VersioningModule;
import com.liferay.portal.model.User;
import io.vavr.Lazy;
import io.vavr.control.Try;
Expand All @@ -42,14 +38,7 @@ public class JobUtil {
* Jackson mapper configuration and lazy initialized instance.
*/
private static final Lazy<ObjectMapper> objectMapper = Lazy.of(() -> {
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
mapper.registerModule(new Jdk8Module());
mapper.registerModule(new GuavaModule());
mapper.registerModule(new JavaTimeModule());
mapper.registerModule(new VersioningModule());
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
return mapper;
return DotObjectMapperProvider.getInstance().getIso8610ObjectMapper();
});

private JobUtil() {
Expand Down
51 changes: 3 additions & 48 deletions dotCMS/src/main/java/com/dotcms/publishing/BundlerUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,10 @@
import com.dotmarketing.util.Logger;
import com.dotmarketing.util.UtilMethods;
import com.dotmarketing.util.XMLUtils;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.datatype.guava.GuavaModule;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileNotFoundException;
Expand All @@ -43,14 +32,13 @@
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.file.Files;
import java.time.Instant;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

public class BundlerUtil {

private static ObjectMapper objectMapper;

private static ObjectMapper customMapper;

public static final List<Status> STATUS_TO_RETRY = list(
Expand Down Expand Up @@ -320,19 +308,12 @@ public static void objectToJSON( Object obj, File f, boolean removeFirst ) {
}

private static ObjectMapper getObjectMapper() {
if (objectMapper == null) {
objectMapper = new ObjectMapper();
final JavaTimeModule javaTimeModule = createJavaTimeModule();
objectMapper.registerModule(javaTimeModule);
objectMapper.registerModule(new Jdk8Module());
objectMapper.registerModule(new GuavaModule());
}
return objectMapper;
return DotObjectMapperProvider.getInstance().getDefaultObjectMapper();
}

private static ObjectMapper getCustomMapper() {
if (customMapper == null) {
customMapper = DotObjectMapperProvider.getInstance().getDefaultObjectMapper();
customMapper = getObjectMapper();
}
return customMapper;
}
Expand Down Expand Up @@ -526,30 +507,4 @@ public static boolean tarGzipExists(final String bundleId) {
return bundleTarGzip.exists();
}

private static JavaTimeModule createJavaTimeModule() {
final JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addSerializer(Instant.class, new JsonSerializer<Instant>() {
@Override
public void serialize(final Instant value, final JsonGenerator genarator,
final SerializerProvider serializers)
throws IOException {
genarator.writeNumber(String.valueOf(value.toEpochMilli()));
}
});

javaTimeModule.addDeserializer(Instant.class, new JsonDeserializer<Instant>() {
@Override
public Instant deserialize(final JsonParser parser, final DeserializationContext ctxt)
throws IOException {
try {
final long longValue = parser.getLongValue();
return Instant.ofEpochMilli(longValue);
} catch (JsonParseException e) {
return Instant.parse(parser.getValueAsString());
}
}
});
return javaTimeModule;
}

}
Loading