Skip to content

Commit 7a29c98

Browse files
committed
Add treeToValue(TreeNode, JavaType) overload in ObjectMapper
1 parent bd41ee2 commit 7a29c98

File tree

5 files changed

+82
-17
lines changed

5 files changed

+82
-17
lines changed

src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3256,7 +3256,7 @@ public <T> T treeToValue(TreeNode n, Class<T> valueType)
32563256
// 25-Jan-2019, tatu: [databind#2220] won't prevent existing coercions here
32573257
// Simple cast when we just want to cast to, say, ObjectNode
32583258
if (TreeNode.class.isAssignableFrom(valueType)
3259-
&& valueType.isAssignableFrom(n.getClass())) {
3259+
&& valueType.isAssignableFrom(n.getClass())) {
32603260
return (T) n;
32613261
}
32623262
final JsonToken tt = n.asToken();
@@ -3286,6 +3286,45 @@ public <T> T treeToValue(TreeNode n, Class<T> valueType)
32863286
}
32873287
}
32883288

3289+
/**
3290+
* Same as {@link #treeToValue(TreeNode, Class)} but target type specified
3291+
* using fully resolved {@link JavaType}.
3292+
*
3293+
* @since 2.13
3294+
*/
3295+
@SuppressWarnings("unchecked")
3296+
public <T> T treeToValue(TreeNode n, JavaType valueType)
3297+
throws IllegalArgumentException,
3298+
JsonProcessingException
3299+
{
3300+
// Implementation copied from the type-erased variant
3301+
if (n == null) {
3302+
return null;
3303+
}
3304+
try {
3305+
if (valueType.isTypeOrSubTypeOf(TreeNode.class)
3306+
&& valueType.isTypeOrSuperTypeOf(n.getClass())) {
3307+
return (T) n;
3308+
}
3309+
final JsonToken tt = n.asToken();
3310+
if (tt == JsonToken.VALUE_EMBEDDED_OBJECT) {
3311+
if (n instanceof POJONode) {
3312+
Object ob = ((POJONode) n).getPojo();
3313+
if ((ob == null) || valueType.isTypeOrSuperTypeOf(ob.getClass())) {
3314+
return (T) ob;
3315+
}
3316+
}
3317+
}
3318+
return (T) readValue(treeAsTokens(n), valueType);
3319+
} catch (JsonProcessingException e) {
3320+
// 12-Nov-2020, tatu: These can legit happen, during conversion, especially
3321+
// with things like Builders that validate arguments.
3322+
throw e;
3323+
} catch (IOException e) { // should not occur, no real i/o...
3324+
throw new IllegalArgumentException(e.getMessage(), e);
3325+
}
3326+
}
3327+
32893328
/**
32903329
* Method that is reverse of {@link #treeToValue}: it
32913330
* will convert given Java value (usually bean) into its

src/main/java/com/fasterxml/jackson/databind/ObjectReader.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1975,7 +1975,11 @@ public <T> T treeToValue(TreeNode n, Class<T> valueType) throws JsonProcessingEx
19751975
}
19761976
}
19771977

1978-
// @since 2.13
1978+
/**
1979+
* Same as {@link #treeToValue(TreeNode, Class)} but with type-resolved target value type.
1980+
*
1981+
* @since 2.13
1982+
*/
19791983
public <T> T treeToValue(TreeNode n, JavaType valueType) throws JsonProcessingException
19801984
{
19811985
_assertNotNull("n", n);

src/main/java/com/fasterxml/jackson/databind/deser/std/ReferenceTypeDeserializer.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,11 @@ public Object getEmptyValue(DeserializationContext ctxt) throws JsonMappingExcep
126126
return getNullValue(ctxt);
127127
}
128128

129+
@Override
130+
public Object getAbsentValue(DeserializationContext ctxt) throws JsonMappingException {
131+
return null;
132+
}
133+
129134
public abstract T referenceValue(Object contents);
130135

131136
/**

src/test/java/com/fasterxml/jackson/databind/convert/TestBeanConversions.java

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,12 @@
44
import java.util.Map;
55

66
import com.fasterxml.jackson.core.JsonParser;
7-
import com.fasterxml.jackson.core.TreeNode;
87

98
import com.fasterxml.jackson.databind.*;
109
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
1110
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
1211
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
1312
import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException;
14-
import com.fasterxml.jackson.databind.node.ObjectNode;
1513
import com.fasterxml.jackson.databind.util.StdConverter;
1614

1715
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
@@ -197,17 +195,7 @@ public void testConvertUsingCast() throws Exception
197195
// should just cast...
198196
assertSame(str, result);
199197
}
200-
201-
// [Issue-11]: simple cast, for Tree
202-
public void testNodeConvert() throws Exception
203-
{
204-
ObjectNode src = (ObjectNode) MAPPER.readTree("{}");
205-
TreeNode node = src;
206-
ObjectNode result = MAPPER.treeToValue(node, ObjectNode.class);
207-
// should just cast...
208-
assertSame(src, result);
209-
}
210-
198+
211199
private void _convertAndVerifyPoint(ObjectMapper m)
212200
{
213201
final PointZ input = new PointZ(1, 2, 3);

src/test/java/com/fasterxml/jackson/databind/node/TestConversions.java

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,16 +166,23 @@ public void testTreeToValue() throws Exception
166166
Root r1 = mapper.treeToValue(root, Root.class);
167167
assertNotNull(r1);
168168
assertEquals(13, r1.leaf.value);
169+
170+
// ... also JavaType
171+
r1 = mapper.treeToValue(root, mapper.constructType(Root.class));
172+
assertEquals(13, r1.leaf.value);
169173
}
170174

171175
// [databind#1208]: should coerce POJOs at least at root level
172176
public void testTreeToValueWithPOJO() throws Exception
173177
{
174178
Calendar c = Calendar.getInstance();
175179
c.setTime(new java.util.Date(0));
176-
ValueNode pojoNode = MAPPER.getNodeFactory().pojoNode(c);
180+
final ValueNode pojoNode = MAPPER.getNodeFactory().pojoNode(c);
177181
Calendar result = MAPPER.treeToValue(pojoNode, Calendar.class);
178-
assertNotNull(result);
182+
assertEquals(result.getTimeInMillis(), c.getTimeInMillis());
183+
184+
// and same with JavaType
185+
result = MAPPER.treeToValue(pojoNode, MAPPER.constructType(Calendar.class));
179186
assertEquals(result.getTimeInMillis(), c.getTimeInMillis());
180187
}
181188

@@ -328,10 +335,32 @@ public void testConversionsOfNull() throws Exception
328335
Object pojo = MAPPER.treeToValue(n, Root.class);
329336
assertNull(pojo);
330337

338+
pojo = MAPPER.treeToValue(n, MAPPER.constructType(Root.class));
339+
assertNull(pojo);
340+
331341
// [databind#2972]
332342
AtomicReference<?> result = MAPPER.treeToValue(NullNode.instance,
333343
AtomicReference.class);
334344
assertNotNull(result);
335345
assertNull(result.get());
346+
347+
result = MAPPER.treeToValue(NullNode.instance,
348+
MAPPER.constructType(AtomicReference.class));
349+
assertNotNull(result);
350+
assertNull(result.get());
351+
}
352+
353+
// Simple cast, for Tree
354+
public void testNodeConvert() throws Exception
355+
{
356+
ObjectNode src = (ObjectNode) MAPPER.readTree("{}");
357+
TreeNode node = src;
358+
ObjectNode result = MAPPER.treeToValue(node, ObjectNode.class);
359+
// should just cast...
360+
assertSame(src, result);
361+
362+
// ditto w/ JavaType
363+
result = MAPPER.treeToValue(node, MAPPER.constructType(ObjectNode.class));
364+
assertSame(src, result);
336365
}
337366
}

0 commit comments

Comments
 (0)