Skip to content

Commit

Permalink
Allow GsonBuilder to be passed in and used through Analytics and Anal…
Browse files Browse the repository at this point in the history
…yticsClient (#446)

Co-authored-by: Louis Lepper <[email protected]>
  • Loading branch information
louislepper and llepper2 authored Sep 27, 2023
1 parent de66ffc commit 4e47e76
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 32 deletions.
32 changes: 26 additions & 6 deletions analytics/src/main/java/com/segment/analytics/Analytics.java
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ public static class Builder {
private List<Callback> callbacks;
private int queueCapacity;
private boolean forceTlsV1 = false;
private GsonBuilder gsonBuilder;

Builder(String writeKey) {
if (writeKey == null || writeKey.trim().length() == 0) {
Expand Down Expand Up @@ -248,6 +249,20 @@ public Builder queueCapacity(int capacity) {
this.queueCapacity = capacity;
return this;
}

public Builder gsonBuilder(GsonBuilder gsonBuilder) {
if (gsonBuilder == null) {
throw new NullPointerException("Null gsonBuilder");
}

if (this.gsonBuilder != null) {
throw new IllegalStateException("gsonBuilder is already registered.");
}

this.gsonBuilder = gsonBuilder;
return this;
}

/** Set the queueSize at which flushes should be triggered. */
@Beta
public Builder flushQueueSize(int flushQueueSize) {
Expand Down Expand Up @@ -341,11 +356,15 @@ public Builder forceTlsVersion1() {

/** Create a {@link Analytics} client. */
public Analytics build() {
Gson gson =
new GsonBuilder() //
.registerTypeAdapterFactory(new AutoValueAdapterFactory()) //
.registerTypeAdapter(Date.class, new ISO8601DateAdapter()) //
.create();
if (gsonBuilder == null) {
gsonBuilder = new GsonBuilder();
}

gsonBuilder
.registerTypeAdapterFactory(new AutoValueAdapterFactory())
.registerTypeAdapter(Date.class, new ISO8601DateAdapter());

Gson gson = gsonBuilder.create();

if (endpoint == null) {
if (uploadURL != null) {
Expand Down Expand Up @@ -450,7 +469,8 @@ public void log(String message) {
threadFactory,
networkExecutor,
callbacks,
writeKey);
writeKey,
gson);

return new Analytics(analyticsClient, messageTransformers, messageInterceptors, log);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public class AnalyticsClient {
private static final int BATCH_MAX_SIZE = 1024 * 500;
private static final int MSG_MAX_SIZE = 1024 * 32;
private static final Charset ENCODING = StandardCharsets.UTF_8;
private static Gson gsonInstance;
private Gson gsonInstance;
private static final String instanceId = UUID.randomUUID().toString();

static {
Expand Down Expand Up @@ -80,7 +80,8 @@ public static AnalyticsClient create(
ThreadFactory threadFactory,
ExecutorService networkExecutor,
List<Callback> callbacks,
String writeKey) {
String writeKey,
Gson gsonInstance) {
return new AnalyticsClient(
new LinkedBlockingQueue<Message>(queueCapacity),
uploadUrl,
Expand All @@ -94,7 +95,8 @@ public static AnalyticsClient create(
networkExecutor,
callbacks,
new AtomicBoolean(false),
writeKey);
writeKey,
gsonInstance);
}

public AnalyticsClient(
Expand All @@ -110,7 +112,8 @@ public AnalyticsClient(
ExecutorService networkExecutor,
List<Callback> callbacks,
AtomicBoolean isShutDown,
String writeKey) {
String writeKey,
Gson gsonInstance) {
this.messageQueue = messageQueue;
this.uploadUrl = uploadUrl;
this.service = service;
Expand All @@ -123,6 +126,7 @@ public AnalyticsClient(
this.networkExecutor = networkExecutor;
this.isShutDown = isShutDown;
this.writeKey = writeKey;
this.gsonInstance = gsonInstance;

this.currentQueueSizeInBytes = 0;

Expand All @@ -141,24 +145,10 @@ public void run() {
TimeUnit.MILLISECONDS);
}

/**
* Creating GSON object everytime we check the size seems costly
*
* @return gson instance
*/
public Gson getGsonInstance() {
if (gsonInstance == null) {
gsonInstance = new Gson();
}
return gsonInstance;
}

public int messageSizeInBytes(Message message) {
Gson gson = getGsonInstance();
String stringifiedMessage = gson.toJson(message);
String stringifiedMessage = gsonInstance.toJson(message);

int sizeInBytes = stringifiedMessage.getBytes(ENCODING).length;
return sizeInBytes;
return stringifiedMessage.getBytes(ENCODING).length;
}

private Boolean isBackPressuredAfterSize(int incomingSize) {
Expand Down Expand Up @@ -269,7 +259,7 @@ public void run() {
LinkedList<Message> messages = new LinkedList<>();
AtomicInteger currentBatchSize = new AtomicInteger();
boolean batchSizeLimitReached = false;
int contextSize = getGsonInstance().toJson(CONTEXT).getBytes(ENCODING).length;
int contextSize = gsonInstance.toJson(CONTEXT).getBytes(ENCODING).length;
try {
while (!stop) {
Message message = messageQueue.take();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

import com.google.gson.GsonBuilder;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -167,6 +168,34 @@ public void buildsWithValidInterceptor() {
assertThat(analytics).isNotNull();
}

@Test
public void nullGsonBuilder() {
try {
builder.gsonBuilder(null);
fail("Should fail for null gsonBuilder");
} catch (NullPointerException e) {
assertThat(e).hasMessage("Null gsonBuilder");
}
}

@Test
public void duplicateGsonBuilder() {
GsonBuilder gsonBuilder = new GsonBuilder();
try {
builder.gsonBuilder(gsonBuilder).gsonBuilder(gsonBuilder);
fail("Should fail for duplicate gsonBuilder");
} catch (IllegalStateException e) {
assertThat(e).hasMessage("gsonBuilder is already registered.");
}
}

@Test
public void buildsWithValidGsonBuilder() {
GsonBuilder gsonBuilder = new GsonBuilder();
Analytics analytics = builder.gsonBuilder(gsonBuilder).build();
assertThat(analytics).isNotNull();
}

@Test
public void invalidFlushQueueSize() {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.openMocks;

import com.google.gson.Gson;
import com.segment.analytics.Callback;
import com.segment.analytics.Log;
import com.segment.analytics.TestUtils.MessageBuilderTest;
Expand Down Expand Up @@ -105,7 +106,8 @@ AnalyticsClient newClient() {
networkExecutor,
Collections.singletonList(callback),
isShutDown,
writeKey);
writeKey,
new Gson());
}

@Test
Expand Down Expand Up @@ -293,7 +295,8 @@ public void flushHowManyTimesNecessaryToStayWithinLimit() throws InterruptedExce
networkExecutor,
Collections.singletonList(callback),
isShutDown,
writeKey);
writeKey,
new Gson());

Map<String, String> properties = new HashMap<String, String>();

Expand Down Expand Up @@ -868,7 +871,8 @@ public void submitBatchBelowThreshold() throws InterruptedException, IllegalArgu
networkExecutor,
Collections.singletonList(callback),
isShutDown,
writeKey);
writeKey,
new Gson());

Map<String, String> properties = new HashMap<String, String>();
properties.put("property3", generateDataOfSizeSpecialChars(MAX_MSG_SIZE, true));
Expand Down Expand Up @@ -909,7 +913,8 @@ public void submitBatchAboveThreshold() throws InterruptedException, IllegalArgu
networkExecutor,
Collections.singletonList(callback),
isShutDown,
writeKey);
writeKey,
new Gson());

Map<String, String> properties = new HashMap<String, String>();
properties.put("property3", generateDataOfSizeSpecialChars(MAX_MSG_SIZE, true));
Expand Down Expand Up @@ -949,7 +954,8 @@ public void submitManySmallMessagesBatchAboveThreshold() throws InterruptedExcep
networkExecutor,
Collections.singletonList(callback),
isShutDown,
writeKey);
writeKey,
new Gson());

Map<String, String> properties = new HashMap<String, String>();
properties.put("property3", generateDataOfSizeSpecialChars(1024 * 8, true));
Expand Down

0 comments on commit 4e47e76

Please sign in to comment.