Fixed JsonCodecLoader to manage wrong types

Signed-off-by: slinkydeveloper <francescoguard@gmail.com>
This commit is contained in:
slinkydeveloper
2019-04-11 17:35:54 +02:00
committed by Julien Viet
parent 5b83683c7d
commit 3062540c5d
3 changed files with 158 additions and 19 deletions

View File

@@ -5,8 +5,8 @@ import io.vertx.core.buffer.Buffer;
import java.util.HashMap;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.function.Function;
@SuppressWarnings("unchecked")
public class JsonCodecLoader {
Map<Class, JsonCodec> jsonCodecMap;
@@ -24,22 +24,58 @@ public class JsonCodecLoader {
return new JsonCodecLoader(codecs);
}
@SuppressWarnings("unchecked")
public <T> T decode(Buffer value, Class<T> c) {
Object json = value.toJson();
private <T> JsonCodec retrieveCodec(Class<T> c) {
JsonCodec codec = jsonCodecMap.get(c);
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 {
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> T decodeNaturalNumber(Number number, Class<T> 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> 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));
}
}

View File

@@ -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 class JsonCodecLoaderTest {
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);
}
}

View File

@@ -41,7 +41,7 @@ public class MyJsonObjectPojo {
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