diff --git a/gobblin-api/src/main/java/org/apache/gobblin/util/io/GsonInterfaceAdapter.java b/gobblin-api/src/main/java/org/apache/gobblin/util/io/GsonInterfaceAdapter.java index 5973aa9131..7e66b22f4a 100644 --- a/gobblin-api/src/main/java/org/apache/gobblin/util/io/GsonInterfaceAdapter.java +++ b/gobblin-api/src/main/java/org/apache/gobblin/util/io/GsonInterfaceAdapter.java @@ -40,6 +40,9 @@ import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; +import com.google.gson.JsonParseException; +import com.google.gson.ToNumberStrategy; +import com.google.gson.stream.MalformedJsonException; /** @@ -189,7 +192,38 @@ private S readValue(JsonObject jsonObject, TypeToken defaultTypeToken) th } public static Gson getGson(Class clazz) { - Gson gson = new GsonBuilder().registerTypeAdapterFactory(new GsonInterfaceAdapter(clazz)).create(); + Gson gson = new GsonBuilder() + .setObjectToNumberStrategy(CustomToNumberPolicy.INTEGER_OR_LONG_OR_DOUBLE) + .registerTypeAdapterFactory(new GsonInterfaceAdapter(clazz)) + .create(); return gson; } + + public enum CustomToNumberPolicy implements ToNumberStrategy { + INTEGER_OR_LONG_OR_DOUBLE { + @Override + public Number readNumber(JsonReader in) throws IOException { + String value = in.nextString(); + try { + return Integer.parseInt(value); + } catch (NumberFormatException var3) { + try { + return Long.parseLong(value); + } catch (NumberFormatException var2) { + try { + Double d = Double.valueOf(value); + if ((d.isInfinite() || d.isNaN()) && !in.isLenient()) { + throw new MalformedJsonException("JSON forbids NaN and infinities: " + d + "; at path " + in.getPath()); + } else { + return d; + } + } catch (NumberFormatException var1) { + throw new JsonParseException("Cannot parse " + value + "; at path " + in.getPath(), var1); + } + } + } + } + } + } + } diff --git a/gobblin-api/src/test/java/org/apache/gobblin/util/io/GsonInterfaceAdapterTest.java b/gobblin-api/src/test/java/org/apache/gobblin/util/io/GsonInterfaceAdapterTest.java index 17f1ac0ca0..0eae681c8e 100644 --- a/gobblin-api/src/test/java/org/apache/gobblin/util/io/GsonInterfaceAdapterTest.java +++ b/gobblin-api/src/test/java/org/apache/gobblin/util/io/GsonInterfaceAdapterTest.java @@ -22,6 +22,7 @@ import com.google.common.base.Optional; import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import org.apache.gobblin.util.test.BaseClass; import org.apache.gobblin.util.test.TestClass; @@ -43,4 +44,58 @@ public void test() { } + @Test + public void testObjectToIntegerDeserialize() { + Gson gson = new GsonBuilder().create(); + Integer test = 5; + String ser = gson.toJson(test); + Object deser = gson.fromJson(ser, Object.class); + Assert.assertNotEquals(test, deser); + Assert.assertTrue(deser instanceof Double); + + Gson customGson = new GsonBuilder() + .setObjectToNumberStrategy(GsonInterfaceAdapter.CustomToNumberPolicy.INTEGER_OR_LONG_OR_DOUBLE) + .create(); + + Object deser2 = customGson.fromJson(ser, Object.class); + Assert.assertEquals(test, deser2); + Assert.assertTrue(deser2 instanceof Integer); + } + + @Test + public void testObjectToLongDeserialize() { + Gson gson = new GsonBuilder().create(); + Long test = 1234567890123456789L; + String ser = gson.toJson(test); + Object deser = gson.fromJson(ser, Object.class); + Assert.assertNotEquals(test, deser); + Assert.assertTrue(deser instanceof Double); + + Gson customGson = new GsonBuilder() + .setObjectToNumberStrategy(GsonInterfaceAdapter.CustomToNumberPolicy.INTEGER_OR_LONG_OR_DOUBLE) + .create(); + + Object deser2 = customGson.fromJson(ser, Object.class); + Assert.assertEquals(test, deser2); + Assert.assertTrue(deser2 instanceof Long); + } + + @Test + public void testObjectToDoubleDeserialize() { + Gson gson = new GsonBuilder().create(); + Double test = 5.0; + String ser = gson.toJson(test); + Object deser = gson.fromJson(ser, Object.class); + Assert.assertEquals(test, deser); + Assert.assertTrue(deser instanceof Double); + + Gson customGson = new GsonBuilder() + .setObjectToNumberStrategy(GsonInterfaceAdapter.CustomToNumberPolicy.INTEGER_OR_LONG_OR_DOUBLE) + .create(); + + Object deser2 = customGson.fromJson(ser, Object.class); + Assert.assertEquals(test, deser2); + Assert.assertTrue(deser2 instanceof Double); + } + } diff --git a/gradle/scripts/dependencyDefinitions.gradle b/gradle/scripts/dependencyDefinitions.gradle index 966ef824d7..dbee9aa7b9 100644 --- a/gradle/scripts/dependencyDefinitions.gradle +++ b/gradle/scripts/dependencyDefinitions.gradle @@ -53,7 +53,7 @@ ext.externalDependency = [ "eventhub": "com.microsoft.azure:azure-eventhubs:0.9.0", "guava": "com.google.guava:guava:21.0", "groovy": "org.codehaus.groovy:groovy:2.4.8", - "gson": "com.google.code.gson:gson:2.6.2", + "gson": "com.google.code.gson:gson:2.8.9", "gsonJavatimeSerialisers": "com.fatboyindustrial.gson-javatime-serialisers:gson-javatime-serialisers:1.1.1", "findBugsAnnotations": "com.google.code.findbugs:jsr305:" + findBugsVersion, "hadoopCommon": "org.apache.hadoop:hadoop-common:" + hadoopVersion,