diff --git a/src/main/java/org/stellar/sdk/responses/gson/OperationDeserializer.java b/src/main/java/org/stellar/sdk/responses/gson/OperationDeserializer.java index a34d7ca90..80ea5da5f 100644 --- a/src/main/java/org/stellar/sdk/responses/gson/OperationDeserializer.java +++ b/src/main/java/org/stellar/sdk/responses/gson/OperationDeserializer.java @@ -27,9 +27,15 @@ public OperationResponse deserialize( .registerTypeAdapter(Predicate.class, new PredicateDeserializer()) .create(); - int type = json.getAsJsonObject().get("type_i").getAsInt(); + JsonElement typeElement = json.getAsJsonObject().get("type_i"); + if (typeElement == null || typeElement.isJsonNull()) { + throw new JsonParseException( + "Missing required field 'type_i'. Your Horizon version may be outdated."); + } + int type = typeElement.getAsInt(); if (type < 0 || type >= AllOperationTypes.length) { - throw new IllegalArgumentException("Invalid operation type"); + throw new JsonParseException( + "Unknown operation type: " + type + ". Your SDK version may be outdated."); } switch (AllOperationTypes[type]) { @@ -88,7 +94,7 @@ public OperationResponse deserialize( case RESTORE_FOOTPRINT: return gson.fromJson(json, RestoreFootprintOperationResponse.class); default: - throw new IllegalArgumentException("Invalid operation type"); + throw new AssertionError("Unhandled operation type: " + AllOperationTypes[type]); } } } diff --git a/src/test/java/org/stellar/sdk/responses/OperationResponseTest.java b/src/test/java/org/stellar/sdk/responses/OperationResponseTest.java index 4ebc18f0b..98c614775 100644 --- a/src/test/java/org/stellar/sdk/responses/OperationResponseTest.java +++ b/src/test/java/org/stellar/sdk/responses/OperationResponseTest.java @@ -3,8 +3,10 @@ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; +import com.google.gson.JsonParseException; import java.io.IOException; import java.math.BigInteger; import java.nio.charset.StandardCharsets; @@ -703,4 +705,26 @@ public void testSetTrustLineFlagsOperation() throws IOException { assertArrayEquals(new Integer[] {4}, response.getClearFlags().toArray()); assertArrayEquals(new String[] {"clawback_enabled"}, response.getClearFlagStrings().toArray()); } + + @Test + public void testDeserializeOperationWithMissingTypeI() { + String json = "{\"id\": \"12345\", \"type\": \"payment\"}"; + JsonParseException exception = + assertThrows( + JsonParseException.class, + () -> GsonSingleton.getInstance().fromJson(json, OperationResponse.class)); + assertTrue(exception.getMessage().contains("Missing required field 'type_i'")); + assertTrue(exception.getMessage().contains("Horizon version may be outdated")); + } + + @Test + public void testDeserializeOperationWithUnknownTypeI() { + String json = "{\"id\": \"12345\", \"type\": \"unknown\", \"type_i\": 9999}"; + JsonParseException exception = + assertThrows( + JsonParseException.class, + () -> GsonSingleton.getInstance().fromJson(json, OperationResponse.class)); + assertTrue(exception.getMessage().contains("Unknown operation type: 9999")); + assertTrue(exception.getMessage().contains("SDK version may be outdated")); + } }