diff --git a/release-notes/CREDITS b/release-notes/CREDITS index 67537ccb94..fc773f1a84 100644 --- a/release-notes/CREDITS +++ b/release-notes/CREDITS @@ -629,6 +629,11 @@ Bertrand Renuart (brenuart@github) * Reported #1651: `StdDateFormat` fails to parse 'zulu' date when TimeZone other than UTC (2.8.9) +Kevin Gallardo (newkek@github) + * Reported #1658: Infinite recursion when deserializing a class extending a Map, + with a recursive value type + (2.8.10) + Connor Kuhn (ckuhn@github) * Contributed #1341: FAIL_ON_MISSING_EXTERNAL_TYPE_ID_PROPERTY (2.9.0) diff --git a/release-notes/VERSION b/release-notes/VERSION index 1ebc9a42e7..e39a0dfb83 100644 --- a/release-notes/VERSION +++ b/release-notes/VERSION @@ -8,6 +8,9 @@ Project: jackson-databind #1657: `StdDateFormat` deserializes dates with no tz/offset as UTC instead of configured timezone (reported by Bertrand R) +#1658: Infinite recursion when deserializing a class extending a Map, + with a recursive value type + (reported by Kevin G) 2.8.9 (12-Jun-2017) diff --git a/src/main/java/com/fasterxml/jackson/databind/type/ResolvedRecursiveType.java b/src/main/java/com/fasterxml/jackson/databind/type/ResolvedRecursiveType.java index 12162c57fd..53e061c690 100644 --- a/src/main/java/com/fasterxml/jackson/databind/type/ResolvedRecursiveType.java +++ b/src/main/java/com/fasterxml/jackson/databind/type/ResolvedRecursiveType.java @@ -111,11 +111,22 @@ public String toString() { public boolean equals(Object o) { if (o == this) return true; if (o == null) return false; - // Do NOT ever match unresolved references - if (_referencedType == null) { + if (o.getClass() == getClass()) { + // 16-Jun-2017, tatu: as per [databind#1658], can not do recursive call since + // there is likely to be a cycle... + + // but... true or false? return false; + + /* + // Do NOT ever match unresolved references + if (_referencedType == null) { + return false; + } + return (o.getClass() == getClass() + && _referencedType.equals(((ResolvedRecursiveType) o).getSelfReferencedType())); + */ } - return (o.getClass() == getClass() - && _referencedType.equals(((ResolvedRecursiveType) o).getSelfReferencedType())); + return false; } } diff --git a/src/test/java/com/fasterxml/jackson/databind/type/RecursiveType1658Test.java b/src/test/java/com/fasterxml/jackson/databind/type/RecursiveType1658Test.java new file mode 100644 index 0000000000..c211cd969e --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/databind/type/RecursiveType1658Test.java @@ -0,0 +1,45 @@ +package com.fasterxml.jackson.databind.type; + +import java.util.*; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.jsontype.TypeResolverBuilder; +import com.fasterxml.jackson.databind.jsontype.impl.StdTypeResolverBuilder; + +public class RecursiveType1658Test extends BaseMapTest +{ + @SuppressWarnings("serial") + static class Tree extends HashMap> // implements Serializable + { + public Tree() { } + + public Tree(List children) { + this(); + for (final T t : children) { + this.put(t, new Tree()); + } + } + + public List> getLeafTrees() { + return null; + } + } + + public void testRecursive1658() throws Exception + { + Tree t = new Tree(Arrays.asList("hello", "world")); + ObjectMapper mapper = new ObjectMapper(); + + final TypeResolverBuilder typer = new StdTypeResolverBuilder() + .init(JsonTypeInfo.Id.CLASS, null) + .inclusion(JsonTypeInfo.As.PROPERTY); + mapper.setDefaultTyping(typer); + + String res = mapper.writeValueAsString(t); + + Tree tRead = mapper.readValue(res, Tree.class); + + assertNotNull(tRead); + } +}