diff --git a/src/main/java/org/zendesk/client/v2/Zendesk.java b/src/main/java/org/zendesk/client/v2/Zendesk.java index 4f36493d..76265901 100644 --- a/src/main/java/org/zendesk/client/v2/Zendesk.java +++ b/src/main/java/org/zendesk/client/v2/Zendesk.java @@ -40,6 +40,7 @@ import org.asynchttpclient.Response; import org.asynchttpclient.request.body.multipart.FilePart; import org.asynchttpclient.request.body.multipart.StringPart; +import org.jetbrains.annotations.VisibleForTesting; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.zendesk.client.v2.model.AgentRole; @@ -165,7 +166,8 @@ private Zendesk( String username, String password, Map headers, - int cbpPageSize) { + int cbpPageSize, + Function objectMapperCustomizer) { this.logger = LoggerFactory.getLogger(Zendesk.class); this.closeClient = client == null; this.oauthToken = null; @@ -188,7 +190,7 @@ private Zendesk( headers.putIfAbsent(USER_AGENT_HEADER, new DefaultUserAgent().toString()); this.headers = Collections.unmodifiableMap(headers); this.cbpPageSize = cbpPageSize; - this.mapper = createMapper(); + this.mapper = createMapper(objectMapperCustomizer); } private Zendesk( @@ -196,7 +198,8 @@ private Zendesk( String url, String oauthToken, Map headers, - int cbpPageSize) { + int cbpPageSize, + Function objectMapperCustomizer) { this.logger = LoggerFactory.getLogger(Zendesk.class); this.closeClient = client == null; this.realm = null; @@ -212,7 +215,7 @@ private Zendesk( headers.putIfAbsent(USER_AGENT_HEADER, new DefaultUserAgent().toString()); this.headers = Collections.unmodifiableMap(headers); this.cbpPageSize = cbpPageSize; - this.mapper = createMapper(); + this.mapper = createMapper(objectMapperCustomizer); } ////////////////////////////////////////////////////////////////////// @@ -4206,7 +4209,19 @@ private TemplateUri getSearchUri(Map params, String query, Strin return templateUri; } + /** + * This method did not allow for any customization and its public visibility was likely only for + * tests. If you rely on it for some reason, please report a new issue to discuss options. To + * customize the ObjectMapper, use the {@link Builder#customizeObjectMapper(Function)} method. + */ + @Deprecated(since = "1.3.0", forRemoval = true) public static ObjectMapper createMapper() { + return createMapper(Function.identity()); + } + + @VisibleForTesting + public static ObjectMapper createMapper( + Function objectMapperCustomizer) { ObjectMapper mapper = new ObjectMapper(); mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING); mapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING); @@ -4215,6 +4230,11 @@ public static ObjectMapper createMapper() { mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); mapper.setDateFormat(new StdDateFormat()); mapper.enable(DeserializationFeature.USE_LONG_FOR_INTS); + return objectMapperCustomizer.apply(mapper); + } + + @VisibleForTesting + ObjectMapper getMapper() { return mapper; } @@ -4279,11 +4299,13 @@ public static class Builder { private String token = null; private String oauthToken = null; private int cbpPageSize = DEFAULT_CBP_PAGE_SIZE; + private Function objectMapperCustomizer; private final Map headers; public Builder(String url) { this.url = url; this.headers = new HashMap<>(); + objectMapperCustomizer = Function.identity(); } public Builder setClient(AsyncHttpClient client) { @@ -4339,13 +4361,30 @@ public Builder setCbpPageSize(int cbpPageSize) { return this; } + /** + * Customize the ObjectMapper used by this Zendesk client. Careful, the customizer function will + * be applied after the default configuration for this library. + * + * @param customizer a function that takes an ObjectMapper and returns a customized ObjectMapper + * @return this builder instance + * @since 1.3.0 + */ + public Builder customizeObjectMapper(Function customizer) { + if (customizer != null) { + this.objectMapperCustomizer = customizer; + } + return this; + } + public Zendesk build() { if (token != null) { - return new Zendesk(client, url, username + "/token", token, headers, cbpPageSize); + return new Zendesk( + client, url, username + "/token", token, headers, cbpPageSize, objectMapperCustomizer); } else if (oauthToken != null) { - return new Zendesk(client, url, oauthToken, headers, cbpPageSize); + return new Zendesk(client, url, oauthToken, headers, cbpPageSize, objectMapperCustomizer); } - return new Zendesk(client, url, username, password, headers, cbpPageSize); + return new Zendesk( + client, url, username, password, headers, cbpPageSize, objectMapperCustomizer); } } } diff --git a/src/test/java/org/zendesk/client/v2/SearchTest.java b/src/test/java/org/zendesk/client/v2/SearchTest.java index 0ce4b965..44ffe866 100644 --- a/src/test/java/org/zendesk/client/v2/SearchTest.java +++ b/src/test/java/org/zendesk/client/v2/SearchTest.java @@ -13,6 +13,7 @@ import java.io.UnsupportedEncodingException; import java.util.Arrays; import java.util.Random; +import java.util.function.Function; import org.apache.commons.text.RandomStringGenerator; import org.junit.After; import org.junit.Before; @@ -46,7 +47,7 @@ public class SearchTest { private Zendesk client; // use a mapper that is identical to what the client will use - private ObjectMapper objectMapper = Zendesk.createMapper(); + private ObjectMapper objectMapper = Zendesk.createMapper(Function.identity()); @Before public void setUp() throws Exception { diff --git a/src/test/java/org/zendesk/client/v2/UserTest.java b/src/test/java/org/zendesk/client/v2/UserTest.java index 17b8b15a..012d3da7 100644 --- a/src/test/java/org/zendesk/client/v2/UserTest.java +++ b/src/test/java/org/zendesk/client/v2/UserTest.java @@ -19,6 +19,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.function.Function; import org.apache.commons.text.RandomStringGenerator; import org.junit.After; import org.junit.Before; @@ -50,7 +51,7 @@ public class UserTest { private Zendesk client; // use a mapper that is identical to what the client will use - private ObjectMapper objectMapper = Zendesk.createMapper(); + private ObjectMapper objectMapper = Zendesk.createMapper(Function.identity()); @Before public void setUp() throws Exception { diff --git a/src/test/java/org/zendesk/client/v2/ZendeskTest.java b/src/test/java/org/zendesk/client/v2/ZendeskTest.java new file mode 100644 index 00000000..7aa36487 --- /dev/null +++ b/src/test/java/org/zendesk/client/v2/ZendeskTest.java @@ -0,0 +1,26 @@ +package org.zendesk.client.v2; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +import com.fasterxml.jackson.annotation.JsonInclude; +import org.junit.Test; + +public class ZendeskTest { + + @Test + public void customizeMapper() { + var builder = new Zendesk.Builder("dummy"); + builder.customizeObjectMapper( + om -> om.setSerializationInclusion(JsonInclude.Include.NON_EMPTY)); + + try (var zd = builder.build()) { + var mapper = zd.getMapper(); + assertThat( + mapper.getSerializationConfig().getDefaultPropertyInclusion(), + is( + JsonInclude.Value.construct( + JsonInclude.Include.NON_EMPTY, JsonInclude.Include.NON_EMPTY))); + } + } +} diff --git a/src/test/java/org/zendesk/client/v2/model/LocaleTest.java b/src/test/java/org/zendesk/client/v2/model/LocaleTest.java index d3f27533..bc2b1a04 100644 --- a/src/test/java/org/zendesk/client/v2/model/LocaleTest.java +++ b/src/test/java/org/zendesk/client/v2/model/LocaleTest.java @@ -3,6 +3,7 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; +import java.util.function.Function; import org.junit.Test; import org.zendesk.client.v2.Zendesk; @@ -19,7 +20,7 @@ public void testLocaleDeserialization() throws Exception { + "\"updated_at\": \"2023-09-21T19:23:16Z\"" + "}"; - Locale locale = Zendesk.createMapper().readValue(json, Locale.class); + Locale locale = Zendesk.createMapper(Function.identity()).readValue(json, Locale.class); assertThat(locale.getUrl(), is("https://acme.zendesk.com/api/v2/locales/en-US.json")); assertThat(locale.getId(), is(1L)); diff --git a/src/test/java/org/zendesk/client/v2/model/StatusTest.java b/src/test/java/org/zendesk/client/v2/model/StatusTest.java index 17214dbb..f534e414 100644 --- a/src/test/java/org/zendesk/client/v2/model/StatusTest.java +++ b/src/test/java/org/zendesk/client/v2/model/StatusTest.java @@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectReader; +import java.util.function.Function; import org.junit.Test; import org.zendesk.client.v2.Zendesk; @@ -15,7 +16,7 @@ public class StatusTest { @Test public void serializeAsLowercase() throws Exception { - ObjectMapper mapper = Zendesk.createMapper(); + ObjectMapper mapper = Zendesk.createMapper(Function.identity()); assertThat( mapper.writeValueAsString(Status.PENDING), is("\"" + Status.PENDING.name().toLowerCase() + "\"")); @@ -23,7 +24,7 @@ public void serializeAsLowercase() throws Exception { @Test public void deserializeFromLowercase() throws Exception { - ObjectMapper mapper = Zendesk.createMapper(); + ObjectMapper mapper = Zendesk.createMapper(Function.identity()); ObjectReader reader = mapper.readerFor(Status.class); assertThat( reader.readValue("\"" + Status.PENDING.name().toLowerCase() + "\""), diff --git a/src/test/java/org/zendesk/client/v2/model/TicketTest.java b/src/test/java/org/zendesk/client/v2/model/TicketTest.java index 8296c34d..c8639379 100644 --- a/src/test/java/org/zendesk/client/v2/model/TicketTest.java +++ b/src/test/java/org/zendesk/client/v2/model/TicketTest.java @@ -6,6 +6,7 @@ import java.util.Calendar; import java.util.Date; import java.util.Random; +import java.util.function.Function; import org.junit.Test; import org.zendesk.client.v2.Zendesk; @@ -17,7 +18,7 @@ public class TicketTest { @Test public void serializeWithNullSafeUpdate() throws Exception { - ObjectMapper mapper = Zendesk.createMapper(); + ObjectMapper mapper = Zendesk.createMapper(Function.identity()); Ticket ticket = createSampleTicket(); assertThat(mapper.writeValueAsString(ticket)) .doesNotContain("\"safe_update\"") @@ -26,7 +27,7 @@ public void serializeWithNullSafeUpdate() throws Exception { @Test public void serializeWithFalseSafeUpdate() throws Exception { - ObjectMapper mapper = Zendesk.createMapper(); + ObjectMapper mapper = Zendesk.createMapper(Function.identity()); Ticket ticket = createSampleTicket(); ticket.setSafeUpdate(false); assertThat(mapper.writeValueAsString(ticket)) @@ -36,7 +37,7 @@ public void serializeWithFalseSafeUpdate() throws Exception { @Test public void serializeWithSafeUpdate() throws Exception { - ObjectMapper mapper = Zendesk.createMapper(); + ObjectMapper mapper = Zendesk.createMapper(Function.identity()); Ticket ticket = createSampleTicket(); ticket.setSafeUpdate(true); assertThat(mapper.writeValueAsString(ticket)) diff --git a/src/test/java/org/zendesk/client/v2/model/TimeZoneTest.java b/src/test/java/org/zendesk/client/v2/model/TimeZoneTest.java index 33090d92..984e002a 100644 --- a/src/test/java/org/zendesk/client/v2/model/TimeZoneTest.java +++ b/src/test/java/org/zendesk/client/v2/model/TimeZoneTest.java @@ -10,6 +10,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.function.Function; import org.apache.commons.text.RandomStringGenerator; import org.junit.*; import org.zendesk.client.v2.Zendesk; @@ -31,7 +32,7 @@ public class TimeZoneTest { @Rule public WireMockClassRule zendeskApiMock = zendeskApiClass; private Zendesk client; - private final ObjectMapper objectMapper = Zendesk.createMapper(); + private final ObjectMapper objectMapper = Zendesk.createMapper(Function.identity()); @Before public void setUp() {