diff options
author | Tiago Martins <tiagomartins282@gmail.com> | 2020-07-23 22:44:26 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-07-23 14:44:26 -0700 |
commit | 942aa25950eed2fa297c600c7d15b0b02f6fd8d7 (patch) | |
tree | c877f6cf16a27e66d470f006f9887b9eb9325ce2 | |
parent | 461cd4db9bf02691b1e546dc1d23794501d8cc74 (diff) | |
download | jackson-databind-942aa25950eed2fa297c600c7d15b0b02f6fd8d7.tar.gz |
Support BigInteger and BigDecimal in StdValueInstantiator (#2793)
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); |