From 3062540c5d250dd34fe53cbb1e8351cfabf358c1 Mon Sep 17 00:00:00 2001 From: slinkydeveloper Date: Thu, 11 Apr 2019 17:35:54 +0200 Subject: [PATCH] Fixed JsonCodecLoader to manage wrong types Signed-off-by: slinkydeveloper --- .../io/vertx/core/json/JsonCodecLoader.java | 60 +++++++-- .../vertx/core/json/JsonCodecLoaderTest.java | 115 +++++++++++++++++- .../core/json/codecs/MyJsonObjectPojo.java | 2 +- 3 files changed, 158 insertions(+), 19 deletions(-) diff --git a/src/main/java/io/vertx/core/json/JsonCodecLoader.java b/src/main/java/io/vertx/core/json/JsonCodecLoader.java index e26518a9e77..82729dbac35 100644 --- a/src/main/java/io/vertx/core/json/JsonCodecLoader.java +++ b/src/main/java/io/vertx/core/json/JsonCodecLoader.java @@ -5,8 +5,8 @@ import java.util.HashMap; import java.util.Map; import java.util.ServiceLoader; -import java.util.function.Function; +@SuppressWarnings("unchecked") public class JsonCodecLoader { Map jsonCodecMap; @@ -24,22 +24,58 @@ public static JsonCodecLoader loadCodecsFromSPI() { return new JsonCodecLoader(codecs); } - @SuppressWarnings("unchecked") - public T decode(Buffer value, Class c) { - Object json = value.toJson(); + private JsonCodec retrieveCodec(Class c) { + JsonCodec codec = jsonCodecMap.get(c); + if (codec == null) throw new IllegalStateException("Unable to find codec for class " + c.getName()); + return codec; + } + + public T decode(Object json, Class c) { try { - return (T) jsonCodecMap.get(c).decode(json); - } catch (Exception e) { - throw new IllegalStateException("Unable to find codec for class " + c.getCanonicalName(), e); + return (T) retrieveCodec(c).decode(json); + } catch (ClassCastException e) { + // A codec accepts only a particular type, that could not be the same of json parameter. + // This happens in particular with decodeBuffer(), when jackson decides what he wants for the serialized type + // And it's even worse if someone configure the Jackson mapper to use always float or long or things like these + // That's why these awful tricks + if (json.getClass().equals(Double.class)) { + return (T) retrieveCodec(c).decode(((Double)json).floatValue()); + } + if (json.getClass().equals(Float.class)) { + return (T) retrieveCodec(c).decode(((Float)json).doubleValue()); + } + if (json.getClass().equals(String.class)) { + return (T) retrieveCodec(c).decode(((String)json).charAt(0)); + } + try { + return decodeNaturalNumber((Number)json, c); + } catch (ClassCastException e1) { + throw e; + } } } - @SuppressWarnings("unchecked") - public Buffer encode(Object value) { + private T decodeNaturalNumber(Number number, Class c) { try { - return Buffer.buffer(jsonCodecMap.get(value.getClass()).encode(value).toString()); - } catch (Exception e) { - throw new IllegalStateException("Unable to find codec for class " + value.getClass().getCanonicalName(), e); + return (T) retrieveCodec(c).decode(number.intValue()); + } catch (ClassCastException e) { + try { + return (T) retrieveCodec(c).decode(number.longValue()); + } catch (ClassCastException e1) { + return (T) retrieveCodec(c).decode(number.shortValue()); + } } } + + public T decodeBuffer(Buffer value, Class c) { + return decode(Json.decodeValue(value), c); + } + + public Object encode(Object value) { + return retrieveCodec(value.getClass()).encode(value); + } + + public Buffer encodeBuffer(Object value) { + return Json.encodeToBuffer(encode(value)); + } } diff --git a/src/test/java/io/vertx/core/json/JsonCodecLoaderTest.java b/src/test/java/io/vertx/core/json/JsonCodecLoaderTest.java index d447d033f37..6e894989992 100644 --- a/src/test/java/io/vertx/core/json/JsonCodecLoaderTest.java +++ b/src/test/java/io/vertx/core/json/JsonCodecLoaderTest.java @@ -1,11 +1,10 @@ package io.vertx.core.json; -import io.vertx.core.buffer.Buffer; -import io.vertx.core.json.codecs.MyBooleanPojo; -import io.vertx.core.json.codecs.MyCharPojo; +import io.vertx.core.json.codecs.*; import org.junit.Before; import org.junit.Test; +import static io.vertx.core.json.Json.encodeToBuffer; import static org.junit.Assert.assertEquals; public class JsonCodecLoaderTest { @@ -21,15 +20,119 @@ public void setUp() throws Exception { public void booleanCodecTest() { MyBooleanPojo pojo = new MyBooleanPojo(); pojo.setValue(true); - assertEquals(Buffer.buffer("true"), jsonCodecLoader.encode(pojo)); - assertEquals(pojo, jsonCodecLoader.decode(Buffer.buffer("true"), MyBooleanPojo.class)); + assertEquals(encodeToBuffer(true), jsonCodecLoader.encodeBuffer(pojo)); + assertEquals(pojo, jsonCodecLoader.decodeBuffer(encodeToBuffer(true), MyBooleanPojo.class)); + } + + @Test(expected = ClassCastException.class) + public void booleanCodecWrongTypeTest() { + jsonCodecLoader.decodeBuffer(encodeToBuffer("aaa"), MyBooleanPojo.class); } @Test public void charCodecTest() { MyCharPojo pojo = new MyCharPojo(); pojo.setValue('a'); - assertEquals('a', jsonCodecLoader.decode(Buffer.buffer(new byte[] {(byte)'a'}), MyCharPojo.class)); + assertEquals(encodeToBuffer('a'), jsonCodecLoader.encodeBuffer(pojo)); + assertEquals(pojo, jsonCodecLoader.decodeBuffer(encodeToBuffer('a'), MyCharPojo.class)); + } + + @Test(expected = ClassCastException.class) + public void charCodecWrongTypeTest() { + jsonCodecLoader.decodeBuffer(encodeToBuffer(1), MyCharPojo.class); + } + + @Test + public void doubleCodecTest() { + MyDoublePojo pojo = new MyDoublePojo(); + pojo.setValue(1.2d); + assertEquals(encodeToBuffer(1.2d), jsonCodecLoader.encodeBuffer(pojo)); + assertEquals(pojo, jsonCodecLoader.decodeBuffer(encodeToBuffer(1.2d), MyDoublePojo.class)); + } + + @Test(expected = ClassCastException.class) + public void doubleCodecWrongTypeTest() { + jsonCodecLoader.decodeBuffer(encodeToBuffer(1L), MyDoublePojo.class); + } + + @Test + public void floatCodecTest() { + MyFloatPojo pojo = new MyFloatPojo(); + pojo.setValue(1.2f); + assertEquals(encodeToBuffer(1.2f), jsonCodecLoader.encodeBuffer(pojo)); + assertEquals(pojo, jsonCodecLoader.decodeBuffer(encodeToBuffer(1.2f), MyFloatPojo.class)); + } + + @Test(expected = ClassCastException.class) + public void floatCodecWrongTypeTest() { + jsonCodecLoader.decodeBuffer(encodeToBuffer(1L), MyFloatPojo.class); + } + + @Test + public void intCodecTest() { + MyIntegerPojo pojo = new MyIntegerPojo(); + pojo.setValue(1); + assertEquals(encodeToBuffer((int)1), jsonCodecLoader.encodeBuffer(pojo)); + assertEquals(pojo, jsonCodecLoader.decodeBuffer(encodeToBuffer((int)1), MyIntegerPojo.class)); + } + + @Test(expected = ClassCastException.class) + public void intCodecWrongTypeTest() { + jsonCodecLoader.decodeBuffer(encodeToBuffer(1.2), MyIntegerPojo.class); } + @Test + public void longCodecTest() { + MyLongPojo pojo = new MyLongPojo(); + pojo.setValue(1L); + assertEquals(encodeToBuffer(1L), jsonCodecLoader.encodeBuffer(pojo)); + assertEquals(pojo, jsonCodecLoader.decodeBuffer(encodeToBuffer(1L), MyLongPojo.class)); + } + + @Test(expected = ClassCastException.class) + public void longCodecWrongTypeTest() { + jsonCodecLoader.decodeBuffer(encodeToBuffer(1.2), MyLongPojo.class); + } + + @Test + public void shortCodecTest() { + MyShortPojo pojo = new MyShortPojo(); + pojo.setValue((short)1); + assertEquals(encodeToBuffer((short)1), jsonCodecLoader.encodeBuffer(pojo)); + assertEquals(pojo, jsonCodecLoader.decodeBuffer(encodeToBuffer((short)1), MyShortPojo.class)); + } + + @Test(expected = ClassCastException.class) + public void shortCodecWrongTypeTest() { + jsonCodecLoader.decodeBuffer(encodeToBuffer(1.2), MyShortPojo.class); + } + + @Test + public void jsonArrayCodecTest() { + MyJsonArrayPojo pojo = new MyJsonArrayPojo(); + JsonArray array = new JsonArray().add(1).add(2).add(3); + pojo.setValue(array); + assertEquals(array.toBuffer(), jsonCodecLoader.encodeBuffer(pojo)); + assertEquals(pojo, jsonCodecLoader.decodeBuffer(array.toBuffer(), MyJsonArrayPojo.class)); + } + + @Test(expected = ClassCastException.class) + public void jsonArrayCodecWrongTypeTest() { + jsonCodecLoader.decodeBuffer(encodeToBuffer(2), MyJsonArrayPojo.class); + } + + @Test + public void jsonObjectCodecTest() { + MyJsonObjectPojo pojo = new MyJsonObjectPojo(); + JsonObject obj = new JsonObject().put("a", 1).put("b", "c"); + pojo.setValue(obj); + assertEquals(obj.toBuffer(), jsonCodecLoader.encodeBuffer(pojo)); + assertEquals(pojo, jsonCodecLoader.decodeBuffer(obj.toBuffer(), MyJsonObjectPojo.class)); + } + + @Test(expected = ClassCastException.class) + public void jsonObjectCodecWrongTypeTest() { + jsonCodecLoader.decodeBuffer(encodeToBuffer(2), MyJsonObjectPojo.class); + } + } diff --git a/src/test/java/io/vertx/core/json/codecs/MyJsonObjectPojo.java b/src/test/java/io/vertx/core/json/codecs/MyJsonObjectPojo.java index 8f717754b8a..7939fb1d873 100644 --- a/src/test/java/io/vertx/core/json/codecs/MyJsonObjectPojo.java +++ b/src/test/java/io/vertx/core/json/codecs/MyJsonObjectPojo.java @@ -41,7 +41,7 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; MyJsonObjectPojo that = (MyJsonObjectPojo) o; - return value == that.value; + return Objects.equals(value, that.value); } @Override