Skip to content

Commit e1e7cce

Browse files
committed
Add tests for CoercionConfig wrt int/boolean from "String" (since XML has no native token types for those)
1 parent 3ad3995 commit e1e7cce

File tree

3 files changed

+304
-4
lines changed

3 files changed

+304
-4
lines changed
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
package com.fasterxml.jackson.dataformat.xml.deser.convert;
2+
3+
import java.math.BigInteger;
4+
import java.util.concurrent.atomic.AtomicLong;
5+
6+
import com.fasterxml.jackson.databind.*;
7+
import com.fasterxml.jackson.databind.cfg.CoercionAction;
8+
import com.fasterxml.jackson.databind.cfg.CoercionInputShape;
9+
import com.fasterxml.jackson.databind.type.LogicalType;
10+
11+
import com.fasterxml.jackson.dataformat.xml.XmlTestBase;
12+
13+
// 2020-12-18, tatu: Modified from "jackson-databind" version: XML
14+
// backend MUST NOT prevent coercion from String since XML has no
15+
// native number representation (although TBH JsonParser.isExpectedNumberInt()
16+
// can work around that in many cases)
17+
public class CoerceStringToIntsTest
18+
extends XmlTestBase
19+
{
20+
private final ObjectMapper DEFAULT_MAPPER = newMapper();
21+
private final ObjectMapper MAPPER_LEGACY_FAIL = mapperBuilder()
22+
.disable(MapperFeature.ALLOW_COERCION_OF_SCALARS)
23+
.build();
24+
25+
private final ObjectMapper MAPPER_TO_EMPTY; {
26+
MAPPER_TO_EMPTY = newMapper();
27+
MAPPER_TO_EMPTY.coercionConfigFor(LogicalType.Integer)
28+
.setCoercion(CoercionInputShape.String, CoercionAction.AsEmpty);
29+
}
30+
31+
private final ObjectMapper MAPPER_TRY_CONVERT; {
32+
MAPPER_TRY_CONVERT = newMapper();
33+
MAPPER_TRY_CONVERT.coercionConfigFor(LogicalType.Integer)
34+
.setCoercion(CoercionInputShape.String, CoercionAction.TryConvert);
35+
}
36+
37+
private final ObjectMapper MAPPER_TO_NULL; {
38+
MAPPER_TO_NULL = newMapper();
39+
MAPPER_TO_NULL.coercionConfigFor(LogicalType.Integer)
40+
.setCoercion(CoercionInputShape.String, CoercionAction.AsNull);
41+
}
42+
43+
private final ObjectMapper MAPPER_TO_FAIL; {
44+
MAPPER_TO_FAIL = newMapper();
45+
MAPPER_TO_FAIL.coercionConfigFor(LogicalType.Integer)
46+
.setCoercion(CoercionInputShape.String, CoercionAction.Fail);
47+
}
48+
49+
protected static class BooleanWrapper {
50+
public Boolean b;
51+
52+
public BooleanWrapper() { }
53+
public BooleanWrapper(Boolean value) { b = value; }
54+
}
55+
56+
protected static class IntWrapper {
57+
public int i;
58+
59+
public IntWrapper() { }
60+
public IntWrapper(int value) { i = value; }
61+
}
62+
63+
protected static class LongWrapper {
64+
public long l;
65+
66+
public LongWrapper() { }
67+
public LongWrapper(long value) { l = value; }
68+
}
69+
70+
protected static class DoubleWrapper {
71+
public double d;
72+
73+
public DoubleWrapper() { }
74+
public DoubleWrapper(double value) { d = value; }
75+
}
76+
77+
/*
78+
/********************************************************
79+
/* Test methods, legacy setting
80+
/********************************************************
81+
*/
82+
83+
// Works by default (as per databind defaulting); but also works
84+
// even if seemingly prevented -- this because XML has no native
85+
// number type and Strings present all scalar values, essentially
86+
87+
public void testDefaultStringToIntCoercion() throws Exception {
88+
_verifyLegacyFromStringSucceeds(DEFAULT_MAPPER);
89+
}
90+
91+
public void testLegacyFailStringToInt() throws Exception {
92+
_verifyLegacyFromStringSucceeds(MAPPER_LEGACY_FAIL);
93+
}
94+
95+
private void _verifyLegacyFromStringSucceeds(ObjectMapper mapper) throws Exception
96+
{
97+
// by default, should be ok
98+
Integer I = DEFAULT_MAPPER.readValue("<Integer>28</Integer>", Integer.class);
99+
assertEquals(28, I.intValue());
100+
{
101+
IntWrapper w = DEFAULT_MAPPER.readValue("<IntWrapper><i>37</i></IntWrapper>",
102+
IntWrapper.class);
103+
assertEquals(37, w.i);
104+
}
105+
106+
Long L = DEFAULT_MAPPER.readValue("<Long>39</Long>", Long.class);
107+
assertEquals(39L, L.longValue());
108+
{
109+
LongWrapper w = DEFAULT_MAPPER.readValue("<LongWrapper><l>-13</l></LongWrapper>",
110+
LongWrapper.class);
111+
assertEquals(-13L, w.l);
112+
}
113+
114+
Short S = DEFAULT_MAPPER.readValue("<Short>42</Short>", Short.class);
115+
assertEquals(42, S.intValue());
116+
117+
BigInteger biggie = DEFAULT_MAPPER.readValue("<BigInteger>95007</BigInteger>", BigInteger.class);
118+
assertEquals(95007, biggie.intValue());
119+
120+
AtomicLong atom = DEFAULT_MAPPER.readValue("<AtomicLong>25236</AtomicLong>", AtomicLong.class);
121+
assertEquals(25236L, atom.get());
122+
}
123+
124+
/*
125+
/********************************************************
126+
/* Test methods, CoerceConfig, integers-from-String
127+
/********************************************************
128+
*/
129+
130+
// When explicitly enabled, should pass
131+
132+
public void testCoerceConfigStringToNull() throws Exception {
133+
_verifyCoercionFromStringSucceeds(MAPPER_TO_NULL);
134+
}
135+
136+
// But even if blocked, or changed to null, should pass since with
137+
// XML, "String" is a native representation of numbers
138+
139+
public void testCoerceConfigStringToEmpty() throws Exception {
140+
_verifyCoercionFromStringSucceeds(MAPPER_TO_EMPTY);
141+
}
142+
143+
public void testCoerceConfigStringConvert() throws Exception {
144+
_verifyCoercionFromStringSucceeds(MAPPER_TRY_CONVERT);
145+
}
146+
147+
public void testCoerceConfigFailFromString() throws Exception {
148+
_verifyCoercionFromStringSucceeds(MAPPER_TO_FAIL);
149+
}
150+
151+
private void _verifyCoercionFromStringSucceeds(ObjectMapper mapper) throws Exception
152+
{
153+
assertEquals(Integer.valueOf(12), mapper.readValue("<Integer>12</Integer>", Integer.class));
154+
assertEquals(Integer.valueOf(34), mapper.readValue("<int>34</int>", Integer.TYPE));
155+
{
156+
IntWrapper w = mapper.readValue( "<IntWrapper i='-225' />", IntWrapper.class);
157+
assertEquals(-225, w.i);
158+
}
159+
160+
assertEquals(Long.valueOf(34), mapper.readValue("<Long>34</Long>", Long.class));
161+
assertEquals(Long.valueOf(534), mapper.readValue("<long>534</long>", Long.TYPE));
162+
{
163+
LongWrapper w = mapper.readValue("<LongWrapper><l>-225</l></LongWrapper>",
164+
LongWrapper.class);
165+
assertEquals(-225L, w.l);
166+
}
167+
168+
assertEquals(Short.valueOf((short)12), mapper.readValue("<Short>12</Short>", Short.class));
169+
assertEquals(Short.valueOf((short) 344), mapper.readValue("<short>344</short>", Short.TYPE));
170+
171+
assertEquals(Byte.valueOf((byte)12), mapper.readValue("<Byte>12</Byte>", Byte.class));
172+
assertEquals(Byte.valueOf((byte) -99), mapper.readValue("<byte>-99</byte>", Byte.TYPE));
173+
174+
assertEquals(BigInteger.valueOf(1242L),
175+
mapper.readValue("<BigInteger>1242</BigInteger>", BigInteger.class));
176+
}
177+
}
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
package com.fasterxml.jackson.dataformat.xml.deser.convert;
2+
3+
import java.io.IOException;
4+
import java.util.concurrent.atomic.AtomicBoolean;
5+
6+
import com.fasterxml.jackson.databind.*;
7+
import com.fasterxml.jackson.databind.cfg.CoercionAction;
8+
import com.fasterxml.jackson.databind.cfg.CoercionInputShape;
9+
import com.fasterxml.jackson.databind.type.LogicalType;
10+
11+
import com.fasterxml.jackson.dataformat.xml.XmlTestBase;
12+
13+
// 2020-12-18, tatu: Modified from "jackson-databind" version: XML
14+
// backend MUST NOT prevent coercion from String since XML has no
15+
// native boolean representation
16+
public class CoerceToBooleanTest
17+
extends XmlTestBase
18+
{
19+
static class BooleanPOJO {
20+
public boolean value;
21+
22+
public void setValue(boolean v) { value = v; }
23+
}
24+
25+
private final ObjectMapper DEFAULT_MAPPER = newMapper();
26+
27+
private final ObjectMapper MAPPER_STRING_TO_BOOLEAN_FAIL; {
28+
MAPPER_STRING_TO_BOOLEAN_FAIL = newMapper();
29+
MAPPER_STRING_TO_BOOLEAN_FAIL.coercionConfigFor(LogicalType.Boolean)
30+
.setCoercion(CoercionInputShape.String, CoercionAction.Fail);
31+
}
32+
33+
private final ObjectMapper MAPPER_EMPTY_TO_BOOLEAN_FAIL; {
34+
MAPPER_EMPTY_TO_BOOLEAN_FAIL = newMapper();
35+
MAPPER_EMPTY_TO_BOOLEAN_FAIL.coercionConfigFor(LogicalType.Boolean)
36+
.setCoercion(CoercionInputShape.EmptyString, CoercionAction.Fail);
37+
}
38+
39+
/*
40+
/**********************************************************
41+
/* Test methods: default, legacy configuration, from String
42+
/**********************************************************
43+
*/
44+
45+
// for [databind#403]
46+
public void testEmptyStringFailForBooleanPrimitive() throws IOException
47+
{
48+
final ObjectReader reader = MAPPER_EMPTY_TO_BOOLEAN_FAIL
49+
.readerFor(BooleanPOJO.class);
50+
try {
51+
reader.readValue("<BooleanPOJO><value></value></BooleanPOJO>");
52+
fail("Expected failure for boolean + empty String");
53+
} catch (JsonMappingException e) {
54+
verifyException(e, "Cannot coerce empty String");
55+
verifyException(e, "to `boolean` value");
56+
}
57+
}
58+
59+
public void testDefaultStringToBooleanCoercionOk() throws Exception {
60+
_verifyStringToBooleanOk(DEFAULT_MAPPER);
61+
}
62+
63+
/*
64+
/**********************************************************
65+
/* Test methods: CoercionConfig, from String
66+
/**********************************************************
67+
*/
68+
69+
public void testStringToBooleanOkDespiteCoercionConfig() throws Exception {
70+
_verifyStringToBooleanOk(MAPPER_STRING_TO_BOOLEAN_FAIL);
71+
}
72+
73+
/*
74+
/**********************************************************
75+
/* Verification
76+
/**********************************************************
77+
*/
78+
79+
public void _verifyStringToBooleanOk(ObjectMapper mapper) throws Exception
80+
{
81+
// first successful coercions, basic types:
82+
_verifyCoerceSuccess(mapper, _xmlWrapped("boolean", "true"), Boolean.TYPE, Boolean.TRUE);
83+
_verifyCoerceSuccess(mapper, _xmlWrapped("boolean", "false"), Boolean.TYPE, Boolean.FALSE);
84+
85+
_verifyCoerceSuccess(mapper, _xmlWrapped("Boolean", "true"), Boolean.class, Boolean.TRUE);
86+
_verifyCoerceSuccess(mapper, _xmlWrapped("Boolean", "false"), Boolean.class, Boolean.FALSE);
87+
88+
// and then allowed variants:
89+
_verifyCoerceSuccess(mapper, _xmlWrapped("boolean", "True"), Boolean.TYPE, Boolean.TRUE);
90+
_verifyCoerceSuccess(mapper, _xmlWrapped("Boolean", "True"), Boolean.class, Boolean.TRUE);
91+
_verifyCoerceSuccess(mapper, _xmlWrapped("boolean", "TRUE"), Boolean.TYPE, Boolean.TRUE);
92+
_verifyCoerceSuccess(mapper, _xmlWrapped("Boolean", "TRUE"), Boolean.class, Boolean.TRUE);
93+
_verifyCoerceSuccess(mapper, _xmlWrapped("boolean", "False"), Boolean.TYPE, Boolean.FALSE);
94+
_verifyCoerceSuccess(mapper, _xmlWrapped("Boolean", "False"), Boolean.class, Boolean.FALSE);
95+
_verifyCoerceSuccess(mapper, _xmlWrapped("boolean", "FALSE"), Boolean.TYPE, Boolean.FALSE);
96+
_verifyCoerceSuccess(mapper, _xmlWrapped("Boolean", "FALSE"), Boolean.class, Boolean.FALSE);
97+
98+
// and then Special boolean derivatives:
99+
// Alas, AtomicBoolean.equals() does not work so...
100+
final ObjectReader r = mapper.readerFor(AtomicBoolean.class);
101+
102+
AtomicBoolean ab = r.readValue(_xmlWrapped("AtomicBoolean", "true"));
103+
assertTrue(ab.get());
104+
105+
ab = r.readValue(_xmlWrapped("AtomicBoolean", "false"));
106+
assertFalse(ab.get());
107+
}
108+
109+
/*
110+
/**********************************************************
111+
/* Other helper methods
112+
/**********************************************************
113+
*/
114+
115+
private String _xmlWrapped(String element, String value) {
116+
return String.format("<%s>%s</%s>", element, value, element);
117+
}
118+
119+
private void _verifyCoerceSuccess(ObjectMapper mapper,
120+
String input, Class<?> type, Object exp) throws IOException
121+
{
122+
Object result = mapper.readerFor(type)
123+
.readValue(input);
124+
assertEquals(exp.getClass(), result.getClass());
125+
assertEquals(exp, result);
126+
}
127+
}

src/test/java/com/fasterxml/jackson/dataformat/xml/lists/EmptyListDeserTest.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,8 @@
22

33
import java.util.ArrayList;
44
import java.util.List;
5-
import java.util.Map;
6-
import java.util.Set;
75

86
import com.fasterxml.jackson.annotation.JsonProperty;
9-
import com.fasterxml.jackson.annotation.JsonSetter;
10-
import com.fasterxml.jackson.annotation.Nulls;
117
import com.fasterxml.jackson.core.type.TypeReference;
128

139
import com.fasterxml.jackson.dataformat.xml.*;

0 commit comments

Comments
 (0)