Skip to content

Commit

Permalink
feat: add support for BigDecimal to CustomClassMapper (#196)
Browse files Browse the repository at this point in the history
  • Loading branch information
athakor committed May 6, 2020
1 parent 1e05de4 commit a471f1e
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 7 deletions.
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 {
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));
}

@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

0 comments on commit a471f1e

Please sign in to comment.