Skip to content

Commit

Permalink
Deserialize integer/long JSON into double single-arg constructors #4453
Browse files Browse the repository at this point in the history
  • Loading branch information
davidmoten committed Apr 8, 2024
1 parent 199d3ac commit 64e6697
Show file tree
Hide file tree
Showing 2 changed files with 210 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,18 @@ arg, rewrapCtorProblem(ctxt, t0)
);
}
}


if (_fromDoubleCreator != null) {
Object arg = Double.valueOf(value);
try {
return _fromDoubleCreator.call1(arg);
} catch (Exception t0) {
return ctxt.handleInstantiationProblem(_fromDoubleCreator.getDeclaringClass(),
arg, rewrapCtorProblem(ctxt, t0)
);
}
}

return super.createFromInt(ctxt, value);
}

Expand Down Expand Up @@ -411,6 +422,18 @@ arg, rewrapCtorProblem(ctxt, t0)
);
}
}

// can lose precision
if (_fromDoubleCreator != null) {
Object arg = Double.valueOf(value);
try {
return _fromDoubleCreator.call1(arg);
} catch (Exception t0) {
return ctxt.handleInstantiationProblem(_fromDoubleCreator.getDeclaringClass(),
arg, rewrapCtorProblem(ctxt, t0)
);
}
}

return super.createFromLong(ctxt, value);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
package com.fasterxml.jackson.databind.deser.std;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.math.BigDecimal;
import java.math.BigInteger;

import org.junit.Assert;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.exc.ValueInstantiationException;

// [databind#2978]
public class StdValueInstantiatorTest
{
private static final long LONG_TEST_VALUE = 12345678901L;

@Test
public void testDoubleValidation_valid() {
assertEquals(0d, StdValueInstantiator.tryConvertToDouble(BigDecimal.ZERO));
Expand All @@ -23,4 +33,178 @@ public void testDoubleValidation_invalid() {
BigDecimal value = BigDecimal.valueOf(Double.MAX_VALUE).add(BigDecimal.valueOf(Double.MAX_VALUE));
assertNull(StdValueInstantiator.tryConvertToDouble(value));
}

@Test
public void testJsonIntegerToDouble() throws JsonMappingException, JsonProcessingException {
ObjectMapper m = new ObjectMapper();
Stuff a = m.readValue("5", Stuff.class);
assertEquals(5, a.value);
}

@Test
public void testJsonLongToDouble() throws JsonMappingException, JsonProcessingException {
ObjectMapper m = new ObjectMapper();
assertTrue(LONG_TEST_VALUE > Integer.MAX_VALUE);
Stuff a = m.readValue(String.valueOf(LONG_TEST_VALUE), Stuff.class);
assertEquals(LONG_TEST_VALUE, a.value);
}

static class Stuff {
final double value;

Stuff(double value) {
this.value = value;
}
}

@Test
public void testJsonIntegerDeserializationPrefersInt() throws JsonMappingException, JsonProcessingException {
ObjectMapper m = new ObjectMapper();
A a = m.readValue("5", A.class);
assertEquals(1, a.creatorType);
}

static class A {
final int creatorType;

A(int value) {
this.creatorType = 1;
}

A(long value) {
this.creatorType = 2;
}

A(BigInteger value) {
this.creatorType = 3;
}

A(double value) {
this.creatorType = 4;
}
}

@Test
public void testJsonIntegerDeserializationPrefersLong() throws JsonMappingException, JsonProcessingException {
ObjectMapper m = new ObjectMapper();
B a = m.readValue("5", B.class);
assertEquals(2, a.creatorType);
}

static class B {
final int creatorType;

B(long value) {
this.creatorType = 2;
}

B(BigInteger value) {
this.creatorType = 3;
}

B(double value) {
this.creatorType = 4;
}
}

@Test
public void testJsonIntegerDeserializationPrefersBigInteger() throws JsonMappingException, JsonProcessingException {
ObjectMapper m = new ObjectMapper();
C a = m.readValue("5", C.class);
assertEquals(3, a.creatorType);
}

static class C {
final int creatorType;

C(BigInteger value) {
this.creatorType = 3;
}

C(double value) {
this.creatorType = 4;
}
}

@Test
public void testJsonLongDeserializationPrefersLong() throws JsonMappingException, JsonProcessingException {
ObjectMapper m = new ObjectMapper();
A2 a = m.readValue(String.valueOf(LONG_TEST_VALUE), A2.class);
assertEquals(2, a.creatorType);
}

static class A2 {
final int creatorType;

A2(int value) {
this.creatorType = 1;
}

A2(long value) {
this.creatorType = 2;
}

A2(BigInteger value) {
this.creatorType = 3;
}

A2(double value) {
this.creatorType = 4;
}
}

@Test
public void testJsonLongDeserializationPrefersBigInteger() throws JsonMappingException, JsonProcessingException {
ObjectMapper m = new ObjectMapper();
B2 a = m.readValue(String.valueOf(LONG_TEST_VALUE), B2.class);
assertEquals(3, a.creatorType);
}

static class B2 {
final int creatorType;

B2(int value) {
this.creatorType = 1;
}

B2(BigInteger value) {
this.creatorType = 3;
}

B2(double value) {
this.creatorType = 4;
}
}

@Test
public void testJsonIntegerIntoDoubleConstructorThrows() throws JsonMappingException, JsonProcessingException {
ObjectMapper m = new ObjectMapper();
try {
m.readValue("5", D.class);
Assert.fail();
} catch (ValueInstantiationException e) {
assertTrue(e.getCause() instanceof IllegalArgumentException);
assertEquals("boo", e.getCause().getMessage());
}
}

static final class D {

D(double value) {
throw new IllegalArgumentException("boo");
}
}

@Test
public void testJsonLongIntoDoubleConstructorThrows() throws JsonMappingException, JsonProcessingException {
ObjectMapper m = new ObjectMapper();
try {
m.readValue(String.valueOf(LONG_TEST_VALUE), D.class);
Assert.fail();
} catch (ValueInstantiationException e) {
assertTrue(e.getCause() instanceof IllegalArgumentException);
assertEquals("boo", e.getCause().getMessage());
}
}

}

0 comments on commit 64e6697

Please sign in to comment.