Skip to content

Commit

Permalink
Fixed JsonCodecLoader to manage wrong types
Browse files Browse the repository at this point in the history
Signed-off-by: slinkydeveloper <francescoguard@gmail.com>
  • Loading branch information
slinkydeveloper authored and vietj committed Jun 5, 2019
1 parent 5b83683 commit 3062540
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 19 deletions.
60 changes: 48 additions & 12 deletions src/main/java/io/vertx/core/json/JsonCodecLoader.java
Expand Up @@ -5,8 +5,8 @@
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.ServiceLoader; import java.util.ServiceLoader;
import java.util.function.Function;


@SuppressWarnings("unchecked")
public class JsonCodecLoader { public class JsonCodecLoader {


Map<Class, JsonCodec> jsonCodecMap; Map<Class, JsonCodec> jsonCodecMap;
Expand All @@ -24,22 +24,58 @@ public static JsonCodecLoader loadCodecsFromSPI() {
return new JsonCodecLoader(codecs); return new JsonCodecLoader(codecs);
} }


@SuppressWarnings("unchecked") private <T> JsonCodec retrieveCodec(Class<T> c) {
public <T> T decode(Buffer value, Class<T> c) { JsonCodec codec = jsonCodecMap.get(c);
Object json = value.toJson(); if (codec == null) throw new IllegalStateException("Unable to find codec for class " + c.getName());
return codec;
}

public <T> T decode(Object json, Class<T> c) {
try { try {
return (T) jsonCodecMap.get(c).decode(json); return (T) retrieveCodec(c).decode(json);
} catch (Exception e) { } catch (ClassCastException e) {
throw new IllegalStateException("Unable to find codec for class " + c.getCanonicalName(), 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") private <T> T decodeNaturalNumber(Number number, Class<T> c) {
public Buffer encode(Object value) {
try { try {
return Buffer.buffer(jsonCodecMap.get(value.getClass()).encode(value).toString()); return (T) retrieveCodec(c).decode(number.intValue());
} catch (Exception e) { } catch (ClassCastException e) {
throw new IllegalStateException("Unable to find codec for class " + value.getClass().getCanonicalName(), e); try {
return (T) retrieveCodec(c).decode(number.longValue());
} catch (ClassCastException e1) {
return (T) retrieveCodec(c).decode(number.shortValue());
}
} }
} }

public <T> T decodeBuffer(Buffer value, Class<T> 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));
}
} }
115 changes: 109 additions & 6 deletions src/test/java/io/vertx/core/json/JsonCodecLoaderTest.java
@@ -1,11 +1,10 @@
package io.vertx.core.json; package io.vertx.core.json;


import io.vertx.core.buffer.Buffer; import io.vertx.core.json.codecs.*;
import io.vertx.core.json.codecs.MyBooleanPojo;
import io.vertx.core.json.codecs.MyCharPojo;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;


import static io.vertx.core.json.Json.encodeToBuffer;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;


public class JsonCodecLoaderTest { public class JsonCodecLoaderTest {
Expand All @@ -21,15 +20,119 @@ public void setUp() throws Exception {
public void booleanCodecTest() { public void booleanCodecTest() {
MyBooleanPojo pojo = new MyBooleanPojo(); MyBooleanPojo pojo = new MyBooleanPojo();
pojo.setValue(true); pojo.setValue(true);
assertEquals(Buffer.buffer("true"), jsonCodecLoader.encode(pojo)); assertEquals(encodeToBuffer(true), jsonCodecLoader.encodeBuffer(pojo));
assertEquals(pojo, jsonCodecLoader.decode(Buffer.buffer("true"), MyBooleanPojo.class)); assertEquals(pojo, jsonCodecLoader.decodeBuffer(encodeToBuffer(true), MyBooleanPojo.class));
}

@Test(expected = ClassCastException.class)
public void booleanCodecWrongTypeTest() {
jsonCodecLoader.decodeBuffer(encodeToBuffer("aaa"), MyBooleanPojo.class);
} }


@Test @Test
public void charCodecTest() { public void charCodecTest() {
MyCharPojo pojo = new MyCharPojo(); MyCharPojo pojo = new MyCharPojo();
pojo.setValue('a'); 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);
}

} }
Expand Up @@ -41,7 +41,7 @@ public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
MyJsonObjectPojo that = (MyJsonObjectPojo) o; MyJsonObjectPojo that = (MyJsonObjectPojo) o;
return value == that.value; return Objects.equals(value, that.value);
} }


@Override @Override
Expand Down

0 comments on commit 3062540

Please sign in to comment.