1 package com.fasterxml.jackson.databind.type;
2 
3 import java.util.ArrayList;
4 
5 import com.fasterxml.jackson.databind.JavaType;
6 
7 /**
8  * Simple helper class used to keep track of 'call stack' for classes being referenced
9  * (as well as unbound variables)
10  *
11  * @since 2.7
12  */
13 public final class ClassStack
14 {
15     protected final ClassStack _parent;
16     protected final Class<?> _current;
17 
18     private ArrayList<ResolvedRecursiveType> _selfRefs;
19 
ClassStack(Class<?> rootType)20     public ClassStack(Class<?> rootType) {
21         this(null, rootType);
22     }
23 
ClassStack(ClassStack parent, Class<?> curr)24     private ClassStack(ClassStack parent, Class<?> curr) {
25         _parent = parent;
26         _current = curr;
27     }
28 
29     /**
30      * @return New stack frame, if addition is ok; null if not
31      */
child(Class<?> cls)32     public ClassStack child(Class<?> cls) {
33         return new ClassStack(this, cls);
34     }
35 
36     /**
37      * Method called to indicate that there is a self-reference from
38      * deeper down in stack pointing into type this stack frame represents.
39      */
addSelfReference(ResolvedRecursiveType ref)40     public void addSelfReference(ResolvedRecursiveType ref)
41     {
42         if (_selfRefs == null) {
43             _selfRefs = new ArrayList<ResolvedRecursiveType>();
44         }
45         _selfRefs.add(ref);
46     }
47 
48     /**
49      * Method called when type that this stack frame represents is
50      * fully resolved, allowing self-references to be completed
51      * (if there are any)
52      */
resolveSelfReferences(JavaType resolved)53     public void resolveSelfReferences(JavaType resolved)
54     {
55         if (_selfRefs != null) {
56             for (ResolvedRecursiveType ref : _selfRefs) {
57                 ref.setReference(resolved);
58             }
59         }
60     }
61 
find(Class<?> cls)62     public ClassStack find(Class<?> cls)
63     {
64         if (_current == cls) return this;
65         for (ClassStack curr = _parent; curr != null; curr = curr._parent) {
66             if (curr._current == cls) {
67                 return curr;
68             }
69         }
70         return null;
71     }
72 
73     @Override
toString()74     public String toString() {
75         StringBuilder sb = new StringBuilder();
76         sb.append("[ClassStack (self-refs: ")
77             .append((_selfRefs == null) ? "0" : String.valueOf(_selfRefs.size()))
78             .append(')')
79                     ;
80         for (ClassStack curr = this; curr != null; curr = curr._parent) {
81             sb.append(' ').append(curr._current.getName());
82         }
83         sb.append(']');
84         return sb.toString();
85     }
86 }
87