aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTiago Martins <tiagomartins282@gmail.com>2020-07-23 22:44:26 +0100
committerGitHub <noreply@github.com>2020-07-23 14:44:26 -0700
commit942aa25950eed2fa297c600c7d15b0b02f6fd8d7 (patch)
treec877f6cf16a27e66d470f006f9887b9eb9325ce2
parent461cd4db9bf02691b1e546dc1d23794501d8cc74 (diff)
downloadjackson-databind-942aa25950eed2fa297c600c7d15b0b02f6fd8d7.tar.gz
Support BigInteger and BigDecimal in StdValueInstantiator (#2793)
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java12
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerBase.java38
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/deser/ValueInstantiator.java47
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/deser/impl/CreatorCollector.java28
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/deser/std/StdValueInstantiator.java125
-rw-r--r--src/test/java/com/fasterxml/jackson/databind/BaseMapTest.java18
-rw-r--r--src/test/java/com/fasterxml/jackson/databind/deser/creators/TestCreators.java14
7 files changed, 239 insertions, 43 deletions
diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java b/src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java
index 96866488b..7890921dc 100644
--- a/src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java
+++ b/src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java
@@ -1,6 +1,8 @@
package com.fasterxml.jackson.databind.deser;
import java.io.Serializable;
+import java.math.BigDecimal;
+import java.math.BigInteger;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicReference;
@@ -948,6 +950,16 @@ nonAnnotatedParamIndex, ctor);
}
return true;
}
+ if (type == BigInteger.class) {
+ if (isCreator || isVisible) {
+ creators.addBigIntegerCreator(ctor, isCreator);
+ }
+ }
+ if (type == BigDecimal.class) {
+ if (isCreator || isVisible) {
+ creators.addBigDecimalCreator(ctor, isCreator);
+ }
+ }
// Delegating Creator ok iff it has @JsonCreator (etc)
if (isCreator) {
creators.addDelegatingCreator(ctor, isCreator, null, 0);
diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerBase.java b/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerBase.java
index fe1008577..b059782e9 100644
--- a/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerBase.java
+++ b/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerBase.java
@@ -1390,15 +1390,19 @@ public abstract class BeanDeserializerBase
}
return _valueInstantiator.createFromLong(ctxt, p.getLongValue());
}
- // actually, could also be BigInteger, so:
- if (delegateDeser != null) {
- Object bean = _valueInstantiator.createUsingDelegate(ctxt,
- delegateDeser.deserialize(p, ctxt));
- if (_injectables != null) {
- injectValues(ctxt, bean);
+ if (nt == NumberType.BIG_INTEGER) {
+ if (delegateDeser != null) {
+ if (!_valueInstantiator.canCreateFromBigInteger()) {
+ Object bean = _valueInstantiator.createUsingDelegate(ctxt, delegateDeser.deserialize(p, ctxt));
+ if (_injectables != null) {
+ injectValues(ctxt, bean);
+ }
+ return bean;
+ }
}
- return bean;
+ return _valueInstantiator.createFromBigInteger(ctxt, p.getBigIntegerValue());
}
+
return ctxt.handleMissingInstantiator(handledType(), getValueInstantiator(), p,
"no suitable creator method found to deserialize from Number value (%s)",
p.getNumberValue());
@@ -1449,12 +1453,22 @@ public abstract class BeanDeserializerBase
}
return _valueInstantiator.createFromDouble(ctxt, p.getDoubleValue());
}
- // actually, could also be BigDecimal, so:
- JsonDeserializer<Object> delegateDeser = _delegateDeserializer();
- if (delegateDeser != null) {
- return _valueInstantiator.createUsingDelegate(ctxt,
- delegateDeser.deserialize(p, ctxt));
+
+ if (t == NumberType.BIG_DECIMAL) {
+ JsonDeserializer<Object> delegateDeser = _delegateDeserializer();
+ if (delegateDeser != null) {
+ if (!_valueInstantiator.canCreateFromBigDecimal()) {
+ Object bean = _valueInstantiator.createUsingDelegate(ctxt, delegateDeser.deserialize(p, ctxt));
+ if (_injectables != null) {
+ injectValues(ctxt, bean);
+ }
+ return bean;
+ }
+ }
+
+ return _valueInstantiator.createFromBigDecimal(ctxt, p.getDecimalValue());
}
+
return ctxt.handleMissingInstantiator(handledType(), getValueInstantiator(), p,
"no suitable creator method found to deserialize from Number value (%s)",
p.getNumberValue());
diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/ValueInstantiator.java b/src/main/java/com/fasterxml/jackson/databind/deser/ValueInstantiator.java
index 572e99bbc..bf5b25c2b 100644
--- a/src/main/java/com/fasterxml/jackson/databind/deser/ValueInstantiator.java
+++ b/src/main/java/com/fasterxml/jackson/databind/deser/ValueInstantiator.java
@@ -8,6 +8,8 @@ import com.fasterxml.jackson.databind.cfg.CoercionInputShape;
import com.fasterxml.jackson.databind.deser.impl.PropertyValueBuffer;
import com.fasterxml.jackson.databind.introspect.AnnotatedWithParams;
import com.fasterxml.jackson.databind.type.LogicalType;
+import java.math.BigDecimal;
+import java.math.BigInteger;
/**
* Class that defines simple API implemented by objects that create value
@@ -138,17 +140,30 @@ public abstract class ValueInstantiator
public boolean canCreateFromLong() { return false; }
/**
+ * Method that can be called to check whether a BigInteger based creator is available
+ * to use (to call {@link #createFromBigInteger}). +
+ */
+ public boolean canCreateFromBigInteger() { return false; }
+
+ /**
* Method that can be called to check whether a double (double / Double) based
* creator is available to use (to call {@link #createFromDouble}).
*/
public boolean canCreateFromDouble() { return false; }
/**
+ * Method that can be called to check whether a BigDecimal based creator is available
+ * to use (to call {@link #createFromBigDecimal}).
+ */
+ public boolean canCreateFromBigDecimal() { return false; }
+
+ /**
* Method that can be called to check whether a double (boolean / Boolean) based
* creator is available to use (to call {@link #createFromDouble}).
*/
public boolean canCreateFromBoolean() { return false; }
+
/**
* Method that can be called to check whether a default creator (constructor,
* or no-arg static factory method)
@@ -263,7 +278,7 @@ public abstract class ValueInstantiator
* {@link PropertyValueBuffer#getParameter(SettableBeanProperty)} to safely
* read the present properties only, and to have some other behavior for the
* missing properties.
- *
+ *
* @since 2.8
*/
public Object createFromObjectWith(DeserializationContext ctxt,
@@ -316,12 +331,28 @@ public abstract class ValueInstantiator
value);
}
+ public Object createFromBigInteger(DeserializationContext ctxt, BigInteger value) throws IOException
+ {
+ return ctxt.handleMissingInstantiator(getValueClass(),this,null,
+ "no BigInteger-argument constructor/factory method to deserialize from Number value (%s)",
+ value
+ );
+ }
+
public Object createFromDouble(DeserializationContext ctxt, double value) throws IOException {
return ctxt.handleMissingInstantiator(getValueClass(), this, null,
"no double/Double-argument constructor/factory method to deserialize from Number value (%s)",
value);
}
+ public Object createFromBigDecimal(DeserializationContext ctxt, BigDecimal value) throws IOException
+ {
+ return ctxt.handleMissingInstantiator(getValueClass(),this,null,
+ "no BigDecimal/double/Double-argument constructor/factory method to deserialize from Number value (%s)",
+ value
+ );
+ }
+
public Object createFromBoolean(DeserializationContext ctxt, boolean value) throws IOException {
return ctxt.handleMissingInstantiator(getValueClass(), this, null,
"no boolean/Boolean-argument constructor/factory method to deserialize from boolean value (%s)",
@@ -444,7 +475,7 @@ public abstract class ValueInstantiator
public Base(JavaType type) {
_valueType = type.getRawClass();
}
-
+
@Override
public String getValueTypeDesc() {
return _valueType.getName();
@@ -468,7 +499,7 @@ public abstract class ValueInstantiator
private static final long serialVersionUID = 1L;
protected final ValueInstantiator _delegate;
-
+
protected Delegating(ValueInstantiator delegate) {
_delegate = delegate;
}
@@ -575,11 +606,21 @@ public abstract class ValueInstantiator
}
@Override
+ public Object createFromBigInteger(DeserializationContext ctxt, BigInteger value) throws IOException {
+ return delegate().createFromBigInteger(ctxt, value);
+ }
+
+ @Override
public Object createFromDouble(DeserializationContext ctxt, double value) throws IOException {
return delegate().createFromDouble(ctxt, value);
}
@Override
+ public Object createFromBigDecimal(DeserializationContext ctxt, BigDecimal value) throws IOException {
+ return delegate().createFromBigDecimal(ctxt, value);
+ }
+
+ @Override
public Object createFromBoolean(DeserializationContext ctxt, boolean value) throws IOException {
return delegate().createFromBoolean(ctxt, value);
}
diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/impl/CreatorCollector.java b/src/main/java/com/fasterxml/jackson/databind/deser/impl/CreatorCollector.java
index 193511992..1928a1af3 100644
--- a/src/main/java/com/fasterxml/jackson/databind/deser/impl/CreatorCollector.java
+++ b/src/main/java/com/fasterxml/jackson/databind/deser/impl/CreatorCollector.java
@@ -21,15 +21,17 @@ public class CreatorCollector {
protected final static int C_STRING = 1;
protected final static int C_INT = 2;
protected final static int C_LONG = 3;
- protected final static int C_DOUBLE = 4;
- protected final static int C_BOOLEAN = 5;
- protected final static int C_DELEGATE = 6;
- protected final static int C_PROPS = 7;
- protected final static int C_ARRAY_DELEGATE = 8;
+ protected final static int C_BIG_INTEGER = 4;
+ protected final static int C_DOUBLE = 5;
+ protected final static int C_BIG_DECIMAL = 6;
+ protected final static int C_BOOLEAN = 7;
+ protected final static int C_DELEGATE = 8;
+ protected final static int C_PROPS = 9;
+ protected final static int C_ARRAY_DELEGATE = 10;
protected final static String[] TYPE_DESCS = new String[] { "default",
- "from-String", "from-int", "from-long", "from-double",
- "from-boolean", "delegate", "property-based", "array-delegate"
+ "from-String", "from-int", "from-long", "from-big-integer", "from-double",
+ "from-big-decimal", "from-boolean", "delegate", "property-based", "array-delegate"
};
// Type of bean being created
@@ -47,7 +49,7 @@ public class CreatorCollector {
*
* @since 2.5
*/
- final protected AnnotatedWithParams[] _creators = new AnnotatedWithParams[9];
+ final protected AnnotatedWithParams[] _creators = new AnnotatedWithParams[11];
/**
* Bitmask of creators that were explicitly marked as creators; false for
@@ -99,7 +101,9 @@ public class CreatorCollector {
inst.configureFromStringCreator(_creators[C_STRING]);
inst.configureFromIntCreator(_creators[C_INT]);
inst.configureFromLongCreator(_creators[C_LONG]);
+ inst.configureFromBigIntegerCreator(_creators[C_BIG_INTEGER]);
inst.configureFromDoubleCreator(_creators[C_DOUBLE]);
+ inst.configureFromBigDecimalCreator(_creators[C_BIG_DECIMAL]);
inst.configureFromBooleanCreator(_creators[C_BOOLEAN]);
return inst;
}
@@ -136,10 +140,18 @@ public class CreatorCollector {
verifyNonDup(creator, C_LONG, explicit);
}
+ public void addBigIntegerCreator(AnnotatedWithParams creator, boolean explicit) {
+ verifyNonDup(creator, C_BIG_INTEGER, explicit);
+ }
+
public void addDoubleCreator(AnnotatedWithParams creator, boolean explicit) {
verifyNonDup(creator, C_DOUBLE, explicit);
}
+ public void addBigDecimalCreator(AnnotatedWithParams creator, boolean explicit) {
+ verifyNonDup(creator, C_BIG_DECIMAL, explicit);
+ }
+
public void addBooleanCreator(AnnotatedWithParams creator, boolean explicit) {
verifyNonDup(creator, C_BOOLEAN, explicit);
}
diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/StdValueInstantiator.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/StdValueInstantiator.java
index 2f4151271..280857cb3 100644
--- a/src/main/java/com/fasterxml/jackson/databind/deser/std/StdValueInstantiator.java
+++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/StdValueInstantiator.java
@@ -8,6 +8,8 @@ import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
import com.fasterxml.jackson.databind.deser.*;
import com.fasterxml.jackson.databind.introspect.AnnotatedWithParams;
import com.fasterxml.jackson.databind.util.ClassUtil;
+import java.math.BigDecimal;
+import java.math.BigInteger;
/**
* Default {@link ValueInstantiator} implementation, which supports
@@ -46,7 +48,7 @@ public class StdValueInstantiator
protected SettableBeanProperty[] _constructorArguments;
// // // Delegate construction
-
+
protected JavaType _delegateType;
protected AnnotatedWithParams _delegateCreator;
protected SettableBeanProperty[] _delegateArguments;
@@ -56,13 +58,15 @@ public class StdValueInstantiator
protected JavaType _arrayDelegateType;
protected AnnotatedWithParams _arrayDelegateCreator;
protected SettableBeanProperty[] _arrayDelegateArguments;
-
+
// // // Scalar construction
protected AnnotatedWithParams _fromStringCreator;
protected AnnotatedWithParams _fromIntCreator;
protected AnnotatedWithParams _fromLongCreator;
+ protected AnnotatedWithParams _fromBigIntegerCreator;
protected AnnotatedWithParams _fromDoubleCreator;
+ protected AnnotatedWithParams _fromBigDecimalCreator;
protected AnnotatedWithParams _fromBooleanCreator;
/*
@@ -106,11 +110,13 @@ public class StdValueInstantiator
_arrayDelegateType = src._arrayDelegateType;
_arrayDelegateCreator = src._arrayDelegateCreator;
_arrayDelegateArguments = src._arrayDelegateArguments;
-
+
_fromStringCreator = src._fromStringCreator;
_fromIntCreator = src._fromIntCreator;
_fromLongCreator = src._fromLongCreator;
+ _fromBigIntegerCreator = src._fromBigIntegerCreator;
_fromDoubleCreator = src._fromDoubleCreator;
+ _fromBigDecimalCreator = src._fromBigDecimalCreator;
_fromBooleanCreator = src._fromBooleanCreator;
}
@@ -153,10 +159,14 @@ public class StdValueInstantiator
_fromLongCreator = creator;
}
+ public void configureFromBigIntegerCreator(AnnotatedWithParams creator) { _fromBigIntegerCreator = creator; }
+
public void configureFromDoubleCreator(AnnotatedWithParams creator) {
_fromDoubleCreator = creator;
}
+ public void configureFromBigDecimalCreator(AnnotatedWithParams creator) { _fromBigDecimalCreator = creator; }
+
public void configureFromBooleanCreator(AnnotatedWithParams creator) {
_fromBooleanCreator = creator;
}
@@ -193,11 +203,17 @@ public class StdValueInstantiator
}
@Override
+ public boolean canCreateFromBigInteger() { return _fromBigIntegerCreator != null; }
+
+ @Override
public boolean canCreateFromDouble() {
return (_fromDoubleCreator != null);
}
@Override
+ public boolean canCreateFromBigDecimal() { return _fromBigDecimalCreator != null; }
+
+ @Override
public boolean canCreateFromBoolean() {
return (_fromBooleanCreator != null);
}
@@ -245,7 +261,7 @@ public class StdValueInstantiator
public SettableBeanProperty[] getFromObjectArguments(DeserializationConfig config) {
return _constructorArguments;
}
-
+
/*
/**********************************************************
/* Public API implementation; instantiation from JSON Object
@@ -345,37 +361,106 @@ public class StdValueInstantiator
arg, rewrapCtorProblem(ctxt, t0));
}
}
+
+ if (_fromBigIntegerCreator != null) {
+ Object arg = BigInteger.valueOf(value);
+ try {
+ return _fromBigIntegerCreator.call1(arg);
+ } catch (Throwable t0) {
+ return ctxt.handleInstantiationProblem(_fromBigIntegerCreator.getDeclaringClass(),
+ arg, rewrapCtorProblem(ctxt, t0)
+ );
+ }
+ }
+
return super.createFromInt(ctxt, value);
}
@Override
public Object createFromLong(DeserializationContext ctxt, long value) throws IOException
{
- if (_fromLongCreator == null) {
- return super.createFromLong(ctxt, value);
+ if (_fromLongCreator != null) {
+ Object arg = Long.valueOf(value);
+ try {
+ return _fromLongCreator.call1(arg);
+ } catch (Throwable t0) {
+ return ctxt.handleInstantiationProblem(_fromLongCreator.getDeclaringClass(),
+ arg,
+ rewrapCtorProblem(ctxt, t0)
+ );
+ }
}
- Object arg = Long.valueOf(value);
- try {
- return _fromLongCreator.call1(arg);
- } catch (Throwable t0) {
- return ctxt.handleInstantiationProblem(_fromLongCreator.getDeclaringClass(),
- arg, rewrapCtorProblem(ctxt, t0));
+
+ if (_fromBigIntegerCreator != null) {
+ Object arg = BigInteger.valueOf(value);
+ try {
+ return _fromBigIntegerCreator.call1(arg);
+ } catch (Throwable t0) {
+ return ctxt.handleInstantiationProblem(_fromBigIntegerCreator.getDeclaringClass(),
+ arg, rewrapCtorProblem(ctxt, t0)
+ );
+ }
}
+
+ return super.createFromLong(ctxt, value);
+ }
+
+ @Override
+ public Object createFromBigInteger(DeserializationContext ctxt, BigInteger value) throws IOException
+ {
+ if (_fromBigDecimalCreator != null) {
+ try {
+ return _fromBigIntegerCreator.call1(value);
+ } catch (Throwable t) {
+ return ctxt.handleInstantiationProblem(_fromBigIntegerCreator.getDeclaringClass(),
+ value, rewrapCtorProblem(ctxt, t)
+ );
+ }
+ }
+
+ return super.createFromBigInteger(ctxt, value);
}
@Override
public Object createFromDouble(DeserializationContext ctxt, double value) throws IOException
{
- if (_fromDoubleCreator == null) {
- return super.createFromDouble(ctxt, value);
+ if(_fromDoubleCreator != null) {
+ Object arg = Double.valueOf(value);
+ try {
+ return _fromDoubleCreator.call1(arg);
+ } catch (Throwable t0) {
+ return ctxt.handleInstantiationProblem(_fromDoubleCreator.getDeclaringClass(),
+ arg, rewrapCtorProblem(ctxt, t0));
+ }
}
- Object arg = Double.valueOf(value);
- try {
- return _fromDoubleCreator.call1(arg);
- } catch (Throwable t0) {
- return ctxt.handleInstantiationProblem(_fromDoubleCreator.getDeclaringClass(),
- arg, rewrapCtorProblem(ctxt, t0));
+
+ if (_fromBigDecimalCreator != null) {
+ Object arg = BigDecimal.valueOf(value);
+ try {
+ return _fromBigDecimalCreator.call1(arg);
+ } catch (Throwable t0) {
+ return ctxt.handleInstantiationProblem(_fromBigDecimalCreator.getDeclaringClass(),
+ arg, rewrapCtorProblem(ctxt, t0));
+ }
}
+
+ return super.createFromDouble(ctxt, value);
+ }
+
+ @Override
+ public Object createFromBigDecimal(DeserializationContext ctxt, BigDecimal value) throws IOException
+ {
+ if (_fromBigDecimalCreator != null) {
+ try {
+ return _fromBigDecimalCreator.call1(value);
+ } catch (Throwable t) {
+ return ctxt.handleInstantiationProblem(_fromBigDecimalCreator.getDeclaringClass(),
+ value, rewrapCtorProblem(ctxt, t)
+ );
+ }
+ }
+
+ return super.createFromBigDecimal(ctxt, value);
}
@Override
diff --git a/src/test/java/com/fasterxml/jackson/databind/BaseMapTest.java b/src/test/java/com/fasterxml/jackson/databind/BaseMapTest.java
index 13aca9c95..8e1925494 100644
--- a/src/test/java/com/fasterxml/jackson/databind/BaseMapTest.java
+++ b/src/test/java/com/fasterxml/jackson/databind/BaseMapTest.java
@@ -1,6 +1,8 @@
package com.fasterxml.jackson.databind;
import java.io.*;
+import java.math.BigDecimal;
+import java.math.BigInteger;
import java.util.*;
import static org.junit.Assert.*;
@@ -58,12 +60,28 @@ public abstract class BaseMapTest
public LongWrapper(long value) { l = value; }
}
+ protected static class BigIntegerWrapper {
+ public BigInteger i;
+
+ public BigIntegerWrapper() { }
+
+ public BigIntegerWrapper(final BigInteger value) { i = value; }
+ }
+
protected static class DoubleWrapper {
public double d;
public DoubleWrapper() { }
public DoubleWrapper(double value) { d = value; }
}
+
+ protected static class BigDecimalWrapper {
+ public BigDecimal d;
+
+ public BigDecimalWrapper() { }
+
+ public BigDecimalWrapper(final BigDecimal value) { d = value; }
+ }
/**
* Simple wrapper around String type, usually to test value
diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/creators/TestCreators.java b/src/test/java/com/fasterxml/jackson/databind/deser/creators/TestCreators.java
index 5b6247855..7c8e389d8 100644
--- a/src/test/java/com/fasterxml/jackson/databind/deser/creators/TestCreators.java
+++ b/src/test/java/com/fasterxml/jackson/databind/deser/creators/TestCreators.java
@@ -1,5 +1,7 @@
package com.fasterxml.jackson.databind.deser.creators;
+import java.math.BigDecimal;
+import java.math.BigInteger;
import java.util.*;
import com.fasterxml.jackson.annotation.*;
@@ -329,6 +331,18 @@ public class TestCreators
assertTrue(bean2.b);
}
+ public void testSimpleBigIntegerConstructor() throws Exception
+ {
+ final BigIntegerWrapper result = MAPPER.readValue("17", BigIntegerWrapper.class);
+ assertEquals(new BigInteger("17"), result.i);
+ }
+
+ public void testSimpleBigDecimalConstructor() throws Exception
+ {
+ final BigDecimalWrapper result = MAPPER.readValue("42.5", BigDecimalWrapper.class);
+ assertEquals(new BigDecimal("42.5"), result.d);
+ }
+
public void testSimpleFactory() throws Exception
{
FactoryBean bean = MAPPER.readValue("{ \"f\" : 0.25 }", FactoryBean.class);