diff --git a/CHANGELOG.md b/CHANGELOG.md
index a59dd9cf..09824dbf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
# CHANGELOG
+## v8.5.1 (2026-01-08)
+
+- Corrects `StatelessRateDeserializer` and `WebhookDeserializer` to treat all camelCase fields like all other models to properly deserialize JSON fields containing underscors
+
## v8.5.0 (2025-12-09)
- Adds the following functions:
@@ -12,6 +16,7 @@
## v8.4.1 (2025-12-01)
- Adds missing `apiKeys` field to `BaseUser`
+- Removes unecessary `SerializedName` entries in `StatelessRate`
## v8.4.0 (2025-11-24)
diff --git a/README.md b/README.md
index d8802f66..52000eba 100644
--- a/README.md
+++ b/README.md
@@ -16,7 +16,7 @@ Add this to your project's POM:
com.easypost
easypost-api-client
- 8.5.0
+ 8.5.1
```
@@ -25,7 +25,7 @@ Add this to your project's POM:
Add this to your project's build file:
```groovy
-implementation "com.easypost:easypost-api-client:8.5.0"
+implementation "com.easypost:easypost-api-client:8.5.1"
```
**NOTE:** [Google Gson](http://code.google.com/p/google-gson/) is required.
diff --git a/VERSION b/VERSION
index 6d289079..f9c71a52 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-8.5.0
+8.5.1
diff --git a/pom.xml b/pom.xml
index 39cdfa20..710fe76a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
com.easypost
easypost-api-client
- 8.5.0
+ 8.5.1
jar
com.easypost:easypost-api-client
diff --git a/src/main/java/com/easypost/Constants.java b/src/main/java/com/easypost/Constants.java
index 68478a87..cbd00f20 100644
--- a/src/main/java/com/easypost/Constants.java
+++ b/src/main/java/com/easypost/Constants.java
@@ -1,5 +1,8 @@
package com.easypost;
+import java.util.HashMap;
+import java.util.List;
+
import com.easypost.exception.APIException;
import com.easypost.http.HashMapSerializer;
import com.easypost.model.AddressVerification;
@@ -16,9 +19,6 @@
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
-import java.util.HashMap;
-import java.util.List;
-
public abstract class Constants {
public static final String EASYPOST_SUPPORT_EMAIL = "support@easypost.com";
@@ -62,12 +62,11 @@ public abstract static class ErrorCodes {
public abstract static class CarrierAccountTypes {
public static final List CARRIER_ACCOUNT_TYPES_WITH_CUSTOM_WORKFLOW = ImmutableList.of(
- "FedexAccount", "FedexSmartpostAccount"
- );
+ "FedexAccount", "FedexSmartpostAccount");
public static final List CARRIER_ACCOUNT_TYPES_WITH_CUSTOM_OAUTH = ImmutableList.of(
- "AmazonShippingAccount", "UpsAccount", "UpsMailInnovationsAccount", "UpsSurepostAccount", "UspsShipAccount"
- );
+ "AmazonShippingAccount", "UpsAccount", "UpsMailInnovationsAccount", "UpsSurepostAccount",
+ "UspsShipAccount");
}
public abstract static class Http {
@@ -77,13 +76,18 @@ public abstract static class Http {
public static final int DEFAULT_READ_TIMEOUT_MILLISECONDS = 60000;
public static final Gson GSON = new GsonBuilder()
+ // Standard model deserializer
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
+ // Core (de)serializers
.registerTypeAdapter(HashMap.class, new HashMapSerializer())
- .registerTypeAdapter(SmartRateCollection.class, new SmartRateCollectionDeserializer())
.registerTypeAdapter(APIException.class, new ErrorDeserializer())
+ // Model custom deserializers
.registerTypeAdapter(AddressVerification.class, new AddressVerificationDeserializer())
+ .registerTypeAdapter(SmartRateCollection.class, new SmartRateCollectionDeserializer())
.registerTypeAdapter(StatelessRate[].class, new StatelessRateDeserializer())
- .registerTypeAdapter(Webhook[].class, new WebhookDeserializer()).create();
+ .registerTypeAdapter(Webhook[].class, new WebhookDeserializer())
+ .create();
+
public static final Gson PRETTY_PRINT_GSON = new GsonBuilder().setPrettyPrinting().serializeNulls()
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
}
diff --git a/src/main/java/com/easypost/model/StatelessRateDeserializer.java b/src/main/java/com/easypost/model/StatelessRateDeserializer.java
index ccf1ae42..02902015 100644
--- a/src/main/java/com/easypost/model/StatelessRateDeserializer.java
+++ b/src/main/java/com/easypost/model/StatelessRateDeserializer.java
@@ -1,14 +1,16 @@
package com.easypost.model;
-import com.google.gson.Gson;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.easypost.Constants;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
-import java.lang.reflect.Type;
-
public final class StatelessRateDeserializer implements JsonDeserializer {
/**
* Deserialize a StatelessRate from a JSON object.
@@ -21,11 +23,20 @@ public final class StatelessRateDeserializer implements JsonDeserializer ratesList = new ArrayList<>();
+ for (JsonElement element : results.getAsJsonArray()) {
+ StatelessRate rate = Constants.Http.GSON.fromJson(element, StatelessRate.class);
+ ratesList.add(rate);
+ }
+
+ return ratesList.toArray(new StatelessRate[0]);
}
}
diff --git a/src/main/java/com/easypost/model/WebhookDeserializer.java b/src/main/java/com/easypost/model/WebhookDeserializer.java
index e32224c0..9e1a02d1 100644
--- a/src/main/java/com/easypost/model/WebhookDeserializer.java
+++ b/src/main/java/com/easypost/model/WebhookDeserializer.java
@@ -1,14 +1,16 @@
package com.easypost.model;
-import com.google.gson.Gson;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.easypost.Constants;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
-import java.lang.reflect.Type;
-
public final class WebhookDeserializer implements JsonDeserializer {
/**
* Deserialize a list of Webhook from a JSON object.
@@ -21,11 +23,20 @@ public final class WebhookDeserializer implements JsonDeserializer {
*/
@Override
public Webhook[] deserialize(final JsonElement json, final Type typeOfT,
- final JsonDeserializationContext context) throws JsonParseException{
+ final JsonDeserializationContext context) throws JsonParseException {
JsonObject jo = json.getAsJsonObject();
JsonElement results = jo.get("webhooks");
- Gson gson = new Gson();
- return gson.fromJson(results, Webhook[].class);
+ if (results == null || !results.isJsonArray()) {
+ return new Webhook[0];
+ }
+
+ List webhooksList = new ArrayList<>();
+ for (JsonElement element : results.getAsJsonArray()) {
+ Webhook webhook = Constants.Http.GSON.fromJson(element, Webhook.class);
+ webhooksList.add(webhook);
+ }
+
+ return webhooksList.toArray(new Webhook[0]);
}
}
diff --git a/src/test/java/com/easypost/BetaRateTest.java b/src/test/java/com/easypost/BetaRateTest.java
index c9c4ed8a..ddaf651e 100644
--- a/src/test/java/com/easypost/BetaRateTest.java
+++ b/src/test/java/com/easypost/BetaRateTest.java
@@ -1,18 +1,19 @@
package com.easypost;
-import com.easypost.exception.EasyPostException;
-import com.easypost.model.StatelessRate;
-import com.easypost.utils.Utilities;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import com.easypost.exception.EasyPostException;
+import com.easypost.model.StatelessRate;
+import com.easypost.utils.Utilities;
public class BetaRateTest {
private static TestUtils.VCR vcr;
@@ -40,7 +41,10 @@ public void testRetrieveStatelessRates() throws EasyPostException {
List rates = vcr.client.betaRate.retrieveStatelessRates(shipment);
- assertTrue(rates.stream().allMatch(rate -> rate != null));
+ // Test that deserialization worked by accessing a field with an underscore
+ for (StatelessRate rate : rates) {
+ assertTrue(rate.getListRate() != null);
+ }
}
/**
@@ -60,8 +64,8 @@ public void testRetrieveLowestStatelessRate() throws EasyPostException {
assertEquals("GroundAdvantage", lowestRate.getService());
List carriers = Arrays.asList("invalidCarrierName");
- EasyPostException exception =
- assertThrows(EasyPostException.class, () -> Utilities.getLowestStatelessRate(rates, carriers, null));
+ EasyPostException exception = assertThrows(EasyPostException.class,
+ () -> Utilities.getLowestStatelessRate(rates, carriers, null));
assertEquals("No rates found.", exception.getMessage());
}
diff --git a/src/test/java/com/easypost/WebhookTest.java b/src/test/java/com/easypost/WebhookTest.java
index 11a57ee4..c35f2400 100644
--- a/src/test/java/com/easypost/WebhookTest.java
+++ b/src/test/java/com/easypost/WebhookTest.java
@@ -1,26 +1,27 @@
package com.easypost;
-import com.easypost.exception.EasyPostException;
-import com.easypost.model.Event;
-import com.easypost.model.Webhook;
-import com.easypost.model.WebhookCustomHeader;
-import com.easypost.utils.Utilities;
-import com.google.common.collect.ImmutableMap;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertInstanceOf;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import com.easypost.exception.EasyPostException;
+import com.easypost.model.Event;
+import com.easypost.model.Webhook;
+import com.easypost.model.WebhookCustomHeader;
+import com.easypost.utils.Utilities;
+import com.google.common.collect.ImmutableMap;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public final class WebhookTest {
@@ -119,6 +120,10 @@ public void testAll() throws EasyPostException {
assertTrue(webhooks.size() > 0);
assertTrue(webhooks.stream().allMatch(webhook -> webhook != null));
+ // Test that deserialization worked by accessing a field with an underscore
+ for (Webhook webhook : webhooks) {
+ assertTrue(webhook.getCreatedAt() != null);
+ }
}
/**