Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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 to properly deserialize JSON fields containing underscors

## v8.5.0 (2025-12-09)

- Adds the following functions:
Expand All @@ -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)

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Add this to your project's POM:
<dependency>
<groupId>com.easypost</groupId>
<artifactId>easypost-api-client</artifactId>
<version>8.5.0</version>
<version>8.5.1</version>
</dependency>
```

Expand All @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
8.5.0
8.5.1
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<groupId>com.easypost</groupId>
<artifactId>easypost-api-client</artifactId>

<version>8.5.0</version>
<version>8.5.1</version>
<packaging>jar</packaging>

<name>com.easypost:easypost-api-client</name>
Expand Down
22 changes: 13 additions & 9 deletions src/main/java/com/easypost/Constants.java
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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 = "[email protected]";
Expand Down Expand Up @@ -62,12 +62,11 @@ public abstract static class ErrorCodes {

public abstract static class CarrierAccountTypes {
public static final List<String> CARRIER_ACCOUNT_TYPES_WITH_CUSTOM_WORKFLOW = ImmutableList.of(
"FedexAccount", "FedexSmartpostAccount"
);
"FedexAccount", "FedexSmartpostAccount");

public static final List<String> CARRIER_ACCOUNT_TYPES_WITH_CUSTOM_OAUTH = ImmutableList.of(
"AmazonShippingAccount", "UpsAccount", "UpsMailInnovationsAccount", "UpsSurepostAccount", "UspsShipAccount"
);
"AmazonShippingAccount", "UpsAccount", "UpsMailInnovationsAccount", "UpsSurepostAccount",
"UspsShipAccount");
}

public abstract static class Http {
Expand All @@ -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();
}
Expand Down
23 changes: 17 additions & 6 deletions src/main/java/com/easypost/model/StatelessRateDeserializer.java
Original file line number Diff line number Diff line change
@@ -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<StatelessRate[]> {
/**
* Deserialize a StatelessRate from a JSON object.
Expand All @@ -21,11 +23,20 @@ public final class StatelessRateDeserializer implements JsonDeserializer<Statele
*/
@Override
public StatelessRate[] 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("rates");
Gson gson = new Gson();

return gson.fromJson(results, StatelessRate[].class);
if (results == null || !results.isJsonArray()) {
return new StatelessRate[0];
}

List<StatelessRate> 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]);
}
}
23 changes: 17 additions & 6 deletions src/main/java/com/easypost/model/WebhookDeserializer.java
Original file line number Diff line number Diff line change
@@ -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<Webhook[]> {
/**
* Deserialize a list of Webhook from a JSON object.
Expand All @@ -21,11 +23,20 @@ public final class WebhookDeserializer implements JsonDeserializer<Webhook[]> {
*/
@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<Webhook> 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]);
}
}
26 changes: 15 additions & 11 deletions src/test/java/com/easypost/BetaRateTest.java
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -40,7 +41,10 @@ public void testRetrieveStatelessRates() throws EasyPostException {

List<StatelessRate> 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);
}
}

/**
Expand All @@ -60,8 +64,8 @@ public void testRetrieveLowestStatelessRate() throws EasyPostException {
assertEquals("GroundAdvantage", lowestRate.getService());

List<String> 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());
}
Expand Down
35 changes: 20 additions & 15 deletions src/test/java/com/easypost/WebhookTest.java
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down Expand Up @@ -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);
}
}

/**
Expand Down
Loading