Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add CustomClassMapper#convertBigDecimal for Deserializer #196

Merged
merged 4 commits into from May 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -35,6 +35,7 @@
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
Expand Down Expand Up @@ -117,11 +118,13 @@ private static <T> Object serialize(T o, ErrorPath path) {
} else if (o instanceof Number) {
if (o instanceof Long || o instanceof Integer || o instanceof Double || o instanceof Float) {
return o;
} else if (o instanceof BigDecimal) {
return String.valueOf(o);
} else {
throw serializeError(
path,
String.format(
"Numbers of type %s are not supported, please use an int, long, float or double",
"Numbers of type %s are not supported, please use an int, long, float, double or BigDecimal",
o.getClass().getSimpleName()));
}
} else if (o instanceof String) {
Expand Down Expand Up @@ -324,6 +327,8 @@ private static <T> T deserializeToPrimitive(
return (T) convertDouble(o, context);
} else if (Long.class.isAssignableFrom(clazz) || long.class.isAssignableFrom(clazz)) {
return (T) convertLong(o, context);
} else if (BigDecimal.class.isAssignableFrom(clazz)) {
return (T) convertBigDecimal(o, context);
} else if (Float.class.isAssignableFrom(clazz) || float.class.isAssignableFrom(clazz)) {
return (T) (Float) convertDouble(o, context).floatValue();
} else {
Expand Down Expand Up @@ -462,6 +467,24 @@ private static Double convertDouble(Object o, DeserializeContext context) {
}
}

private static BigDecimal convertBigDecimal(Object o, DeserializeContext context) {
if (o instanceof Integer) {
return BigDecimal.valueOf(((Integer) o).intValue());
} else if (o instanceof Long) {
return BigDecimal.valueOf(((Long) o).longValue());
} else if (o instanceof Double) {
return BigDecimal.valueOf(((Double) o).doubleValue()).abs();
} else if (o instanceof BigDecimal) {
return (BigDecimal) o;
} else if (o instanceof String) {
return new BigDecimal((String) o);
} else {
BenWhitehead marked this conversation as resolved.
Show resolved Hide resolved
throw deserializeError(
context.errorPath,
"Failed to convert a value of type " + o.getClass().getName() + " to BigDecimal");
}
}

private static Boolean convertBoolean(Object o, DeserializeContext context) {
if (o instanceof Boolean) {
return (Boolean) o;
Expand Down
Expand Up @@ -180,19 +180,19 @@ public void doesNotSerializeAdvancedNumberTypes() {
pojo.bigIntegerValue = new BigInteger("0");
expectedErrorMessages.put(
pojo,
"Could not serialize object. Numbers of type BigInteger are not supported, please use an int, long, float or double (found in field 'bigIntegerValue')");
"Could not serialize object. Numbers of type BigInteger are not supported, please use an int, long, float, double or BigDecimal (found in field 'bigIntegerValue')");

pojo = new InvalidPOJO();
pojo.byteValue = 0;
expectedErrorMessages.put(
pojo,
"Could not serialize object. Numbers of type Byte are not supported, please use an int, long, float or double (found in field 'byteValue')");
"Could not serialize object. Numbers of type Byte are not supported, please use an int, long, float, double or BigDecimal (found in field 'byteValue')");

pojo = new InvalidPOJO();
pojo.shortValue = 0;
expectedErrorMessages.put(
pojo,
"Could not serialize object. Numbers of type Short are not supported, please use an int, long, float or double (found in field 'shortValue')");
"Could not serialize object. Numbers of type Short are not supported, please use an int, long, float, double or BigDecimal (found in field 'shortValue')");

for (Map.Entry<InvalidPOJO, String> testCase : expectedErrorMessages.entrySet()) {
try {
Expand Down
Expand Up @@ -31,6 +31,7 @@
import com.google.common.collect.ImmutableList;
import com.google.firestore.v1.DatabaseRootName;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
Expand All @@ -39,6 +40,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import org.junit.Test;
import org.junit.runner.RunWith;
Expand Down Expand Up @@ -74,6 +76,31 @@ public double getValue() {
}
}

private static class BigDecimalBean {
private BigDecimal value;

public BigDecimal getValue() {
return value;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
BigDecimalBean bean = (BigDecimalBean) o;
return Objects.equals(value, bean.value);
}

@Override
public int hashCode() {
return Objects.hash(value);
}
}

private static class FloatBean {
private float value;

Expand Down Expand Up @@ -1049,6 +1076,41 @@ public void primitiveDeserializeDouble() {
}
}

@Test
public void primitiveDeserializeBigDecimal() {
BigDecimalBean beanBigdecimal = deserialize("{'value': 123}", BigDecimalBean.class);
assertEquals(BigDecimal.valueOf(123), beanBigdecimal.value);

beanBigdecimal = deserialize("{'value': '123'}", BigDecimalBean.class);
assertEquals(BigDecimal.valueOf(123), beanBigdecimal.value);

// Int
BigDecimalBean beanInt = deserialize("{'value': 1}", BigDecimalBean.class);
assertEquals(BigDecimal.valueOf(1), beanInt.value);

// Long
BigDecimalBean beanLong = deserialize("{'value': 1234567890123}", BigDecimalBean.class);
assertEquals(BigDecimal.valueOf(1234567890123L), beanLong.value);

// Double
BigDecimalBean beanDouble = deserialize("{'value': 1.1}", BigDecimalBean.class);
assertEquals(BigDecimal.valueOf(1.1), beanDouble.value);

// Boolean
try {
deserialize("{'value': true}", BigDecimalBean.class);
fail("Should throw");
} catch (RuntimeException e) { // ignore
}

// String
try {
deserialize("{'value': 'foo'}", BigDecimalBean.class);
fail("Should throw");
} catch (RuntimeException e) { // ignore
}
}

@Test
public void primitiveDeserializeFloat() {
FloatBean beanFloat = deserialize("{'value': 1.1}", FloatBean.class);
Expand Down Expand Up @@ -1513,6 +1575,23 @@ public void serializeLongBean() {
assertJson("{'value': 1234567890123}", serialize(bean));
}

@Test
public void serializeBigDecimalBean() {
BigDecimalBean bean = new BigDecimalBean();
bean.value = BigDecimal.valueOf(1.1);
assertEquals(mapAnyType("value", "1.1"), serialize(bean));
}

BenWhitehead marked this conversation as resolved.
Show resolved Hide resolved
@Test
public void bigDecimalRoundTrip() {
BigDecimal doubleMaxPlusOne = BigDecimal.valueOf(Double.MAX_VALUE).add(BigDecimal.ONE);
BigDecimalBean a = new BigDecimalBean();
a.value = doubleMaxPlusOne;
Map<String, Object> serialized = (Map<String, Object>) serialize(a);
BigDecimalBean b = convertToCustomClass(serialized, BigDecimalBean.class);
assertEquals(a, b);
}

@Test
public void serializeBooleanBean() {
BooleanBean bean = new BooleanBean();
Expand Down Expand Up @@ -1827,7 +1906,7 @@ public void shortsCantBeSerialized() {
final ShortBean bean = new ShortBean();
bean.value = 1;
assertExceptionContains(
"Numbers of type Short are not supported, please use an int, long, float or double (found in field 'value')",
"Numbers of type Short are not supported, please use an int, long, float, double or BigDecimal (found in field 'value')",
new Runnable() {
@Override
public void run() {
Expand All @@ -1841,7 +1920,7 @@ public void bytesCantBeSerialized() {
final ByteBean bean = new ByteBean();
bean.value = 1;
assertExceptionContains(
"Numbers of type Byte are not supported, please use an int, long, float or double (found in field 'value')",
"Numbers of type Byte are not supported, please use an int, long, float, double or BigDecimal (found in field 'value')",
new Runnable() {
@Override
public void run() {
Expand Down Expand Up @@ -2478,7 +2557,7 @@ public void serializationFailureIncludesPath() {
} catch (RuntimeException e) {
assertEquals(
"Could not serialize object. Numbers of type Short are not supported, please use an int, "
+ "long, float or double (found in field 'value.inner.value.short')",
+ "long, float, double or BigDecimal (found in field 'value.inner.value.short')",
e.getMessage());
}
}
Expand Down