1 package com.fasterxml.jackson.databind.type;
2 
3 import com.fasterxml.jackson.databind.JavaType;
4 
5 /**
6  * Internal placeholder type used for self-references.
7  *
8  * @since 2.7
9  */
10 public class ResolvedRecursiveType extends TypeBase
11 {
12     private static final long serialVersionUID = 1L;
13 
14     protected JavaType _referencedType;
15 
ResolvedRecursiveType(Class<?> erasedType, TypeBindings bindings)16     public ResolvedRecursiveType(Class<?> erasedType, TypeBindings bindings) {
17         super(erasedType, bindings, null, null, 0, null, null, false);
18     }
19 
setReference(JavaType ref)20     public void setReference(JavaType ref)
21     {
22         // sanity check; should not be called multiple times
23         if (_referencedType != null) {
24             throw new IllegalStateException("Trying to re-set self reference; old value = "+_referencedType+", new = "+ref);
25         }
26         _referencedType = ref;
27     }
28 
29     @Override
getSuperClass()30     public JavaType getSuperClass() {
31         if (_referencedType != null) {
32             return _referencedType.getSuperClass();
33         }
34         return super.getSuperClass();
35     }
36 
getSelfReferencedType()37     public JavaType getSelfReferencedType() { return _referencedType; }
38 
39     // 23-Jul-2019, tatu: [databind#2331] Need to also delegate this...
40     @Override
getBindings()41     public TypeBindings getBindings() {
42         if (_referencedType != null) { // `null` before resolution [databind#2395]
43             return _referencedType.getBindings();
44         }
45         return super.getBindings();
46     }
47 
48     @Override
getGenericSignature(StringBuilder sb)49     public StringBuilder getGenericSignature(StringBuilder sb) {
50         // 30-Oct-2019, tatu: Alas, need to break recursion, otherwise we'll
51         //    end up in StackOverflowError... two choices; '?' for "not known",
52         //    or erased signature.
53         if (_referencedType != null) {
54 //            return _referencedType.getGenericSignature(sb);
55             return _referencedType.getErasedSignature(sb);
56         }
57         return sb.append("?");
58     }
59 
60     @Override
getErasedSignature(StringBuilder sb)61     public StringBuilder getErasedSignature(StringBuilder sb) {
62         if (_referencedType != null) {
63             return _referencedType.getErasedSignature(sb);
64         }
65         return sb;
66     }
67 
68     @Override
withContentType(JavaType contentType)69     public JavaType withContentType(JavaType contentType) {
70         return this;
71     }
72 
73     @Override
withTypeHandler(Object h)74     public JavaType withTypeHandler(Object h) {
75         return this;
76     }
77 
78     @Override
withContentTypeHandler(Object h)79     public JavaType withContentTypeHandler(Object h) {
80         return this;
81     }
82 
83     @Override
withValueHandler(Object h)84     public JavaType withValueHandler(Object h) {
85         return this;
86     }
87 
88     @Override
withContentValueHandler(Object h)89     public JavaType withContentValueHandler(Object h) {
90         return this;
91     }
92 
93     @Override
withStaticTyping()94     public JavaType withStaticTyping() {
95         return this;
96     }
97 
98     @Deprecated // since 2.7
99     @Override
_narrow(Class<?> subclass)100     protected JavaType _narrow(Class<?> subclass) {
101         return this;
102     }
103 
104     @Override
refine(Class<?> rawType, TypeBindings bindings, JavaType superClass, JavaType[] superInterfaces)105     public JavaType refine(Class<?> rawType, TypeBindings bindings,
106             JavaType superClass, JavaType[] superInterfaces) {
107         return null;
108     }
109 
110     @Override
isContainerType()111     public boolean isContainerType() {
112         return false;
113     }
114 
115     @Override
toString()116     public String toString() {
117         StringBuilder sb = new StringBuilder(40)
118                 .append("[recursive type; ");
119         if (_referencedType == null) {
120             sb.append("UNRESOLVED");
121         } else {
122             // [databind#1301]: Typically resolves to a loop so short-cut
123             //   and only include type-erased class
124             sb.append(_referencedType.getRawClass().getName());
125         }
126         return sb.toString();
127     }
128 
129     @Override
equals(Object o)130     public boolean equals(Object o) {
131         if (o == this) return true;
132         if (o == null) return false;
133         if (o.getClass() == getClass()) {
134             // 16-Jun-2017, tatu: as per [databind#1658], cannot do recursive call since
135             //    there is likely to be a cycle...
136 
137             // but... true or false?
138             return false;
139 
140             /*
141             // Do NOT ever match unresolved references
142             if (_referencedType == null) {
143                 return false;
144             }
145             return (o.getClass() == getClass()
146                     && _referencedType.equals(((ResolvedRecursiveType) o).getSelfReferencedType()));
147                     */
148         }
149         return false;
150     }
151 }
152