Skip to content

Problem with JavaType.toString() for recursive (self-referential) types #1301

@voidmain

Description

@voidmain

I'm getting a StackOverflowError when I try to use this class with Jackson:

public class DataDefinition extends HashMap<String, DataDefinition> {
  public DataDefinition definition;
  public DataDefinition elements;
  public String regex;
  public boolean required;
  public String type;
}

Here's a snippet of the stack trace I get:

    at com.fasterxml.jackson.databind.type.ResolvedRecursiveType.toString(ResolvedRecursiveType.java:90)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.fasterxml.jackson.databind.type.MapType.toString(MapType.java:161)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.fasterxml.jackson.databind.type.ResolvedRecursiveType.toString(ResolvedRecursiveType.java:90)
    at java.lang.String.valueOf(String.java:2994)

I did some debugging and found that this looks like the location where the stack track starts:

    public StdValueInstantiator(DeserializationConfig config, JavaType valueType) {
        _valueTypeDesc = (valueType == null) ? "UNKNOWN TYPE" : valueType.toString();
        _valueClass = (valueType == null) ? Object.class : valueType.getRawClass();
    }

It's line 87 in StdValueInstantiator. That looks like it is calling toString() on the on the type and then it goes into an infinite recursion state. I'm not sure why the toString() call is necessary, but it seems like all of this is for debugging and errors and pre-calculating the string is preventing Jackson from working at all even if there isn't an error.

WORK-AROUND: In case anyone looks at this issue and needs a work around, you can use the @JsonAnySetter to fix this issue. Here's the code:

public class DataDefinition {
  public DataDefinition definition;
  public DataDefinition elements;
  @JsonAnySetter
  public Map<String, DataDefinition> properties = new HashMap<>();
  public String regex;
  public boolean required;
  public String type;
}

I also think that this can likely be fixed with code like this:

com.fasterxml.jackson.databind.type.MapType.java#toString()

    public String toString()
    {
        if ((_keyType instance ResolvedRecursiveType && ((ResolvedRecursiveType) _keyType).getSelfReferencedType() == this) || (_valueType instance ResolvedRecursiveType && ((ResolvedRecursiveType) _valueType).getSelfReferencedType() == this)) {
            return "[map type; class "+_class.getName()+", "+_keyType+" -> self]";
        }
        return "[map type; class "+_class.getName()+", "+_keyType+" -> "+_valueType+"]";
    }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions