aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/com/fasterxml/jackson/databind/type/ReferenceType.java
blob: e8c69628cbe19741a5b23fed7333e59766d3e4d8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
package com.fasterxml.jackson.databind.type;

import com.fasterxml.jackson.databind.JavaType;

/**
 * Specialized {@link SimpleType} for types that are referential types,
 * that is, values that can be dereferenced to another value (or null),
 * of different type.
 * Referenced type is accessible using {@link #getContentType()}.
 * 
 * @since 2.6
 */
public class ReferenceType extends SimpleType
{
    private static final long serialVersionUID = 1L;

    protected final JavaType _referencedType;

    /**
     * Essential type used for type ids, for example if type id is needed for
     * referencing type with polymorphic handling. Typically initialized when
     * a {@link SimpleType} is upgraded into reference type, but NOT changed
     * if being sub-classed.
     *
     * @since 2.8
     */
    protected final JavaType _anchorType;

    protected ReferenceType(Class<?> cls, TypeBindings bindings,
            JavaType superClass, JavaType[] superInts, JavaType refType,
            JavaType anchorType,
            Object valueHandler, Object typeHandler, boolean asStatic)
    {
        super(cls, bindings, superClass, superInts, refType.hashCode(),
                valueHandler, typeHandler, asStatic);
        _referencedType = refType;
        _anchorType = (anchorType == null) ? this : anchorType;
    }

    /**
     * Constructor used when upgrading into this type (via {@link #upgradeFrom},
     * the usual way for {@link ReferenceType}s to come into existence.
     * Sets up what is considered the "base" reference type
     *
     * @since 2.7
     */
    protected ReferenceType(TypeBase base, JavaType refType)
    {
        super(base);
        _referencedType = refType;
        // we'll establish this as the anchor type
        _anchorType = this;
    }

    /**
     * Factory method that can be used to "upgrade" a basic type into collection-like
     * one; usually done via {@link TypeModifier}
     * 
     * @param baseType Resolved non-reference type (usually {@link SimpleType}) that is being upgraded
     * @param refdType Referenced type; usually the first and only type parameter, but not necessarily
     *
     * @since 2.7
     */
    public static ReferenceType upgradeFrom(JavaType baseType, JavaType refdType) {
        if (refdType == null) {
            throw new IllegalArgumentException("Missing referencedType");
        }
        // 19-Oct-2015, tatu: Not sure if and how other types could be used as base;
        //    will cross that bridge if and when need be
        if (baseType instanceof TypeBase) {
            return new ReferenceType((TypeBase) baseType, refdType);
        }
        throw new IllegalArgumentException("Can not upgrade from an instance of "+baseType.getClass());
    }

    /**
     * @since 2.7
     */
    public static ReferenceType construct(Class<?> cls, TypeBindings bindings,
            JavaType superClass, JavaType[] superInts, JavaType refType)
    {
        return new ReferenceType(cls, bindings, superClass, superInts,
                refType, null, null, null, false);
    }

    @Deprecated // since 2.7
    public static ReferenceType construct(Class<?> cls, JavaType refType) {
        return new ReferenceType(cls, TypeBindings.emptyBindings(),
                // !!! TODO: missing supertypes
                null, null, null, refType, null, null, false);
    }

    @Override
    public JavaType withContentType(JavaType contentType) {
        if (_referencedType == contentType) {
            return this;
        }
        return new ReferenceType(_class, _bindings, _superClass, _superInterfaces,
                contentType, _anchorType, _valueHandler, _typeHandler, _asStatic);
    }

    @Override
    public ReferenceType withTypeHandler(Object h)
    {
        if (h == _typeHandler) {
            return this;
        }
        return new ReferenceType(_class, _bindings, _superClass, _superInterfaces,
                _referencedType, _anchorType, _valueHandler, h, _asStatic);
    }

    @Override
    public ReferenceType withContentTypeHandler(Object h)
    {
        if (h == _referencedType.<Object>getTypeHandler()) {
            return this;
        }
        return new ReferenceType(_class, _bindings, _superClass, _superInterfaces,
                _referencedType.withTypeHandler(h), _anchorType,
                _valueHandler, _typeHandler, _asStatic);
    }

    @Override
    public ReferenceType withValueHandler(Object h) {
        if (h == _valueHandler) {
            return this;
        }
        return new ReferenceType(_class, _bindings,
                _superClass, _superInterfaces, _referencedType, _anchorType,
                h, _typeHandler,_asStatic);
    }

    @Override
    public ReferenceType withContentValueHandler(Object h) {
        if (h == _referencedType.<Object>getValueHandler()) {
            return this;
        }
        JavaType refdType = _referencedType.withValueHandler(h);
        return new ReferenceType(_class, _bindings,
                _superClass, _superInterfaces, refdType, _anchorType,
                _valueHandler, _typeHandler, _asStatic);
    }

    @Override
    public ReferenceType withStaticTyping() {
        if (_asStatic) {
            return this;
        }
        return new ReferenceType(_class, _bindings, _superClass, _superInterfaces,
                _referencedType.withStaticTyping(), _anchorType,
                 _valueHandler, _typeHandler, true);
    }

    @Override
    public JavaType refine(Class<?> rawType, TypeBindings bindings,
            JavaType superClass, JavaType[] superInterfaces) {
        return new ReferenceType(rawType, _bindings,
                superClass, superInterfaces, _referencedType, _anchorType,
                _valueHandler, _typeHandler, _asStatic);
    }

    @Override
    protected String buildCanonicalName()
    {
        StringBuilder sb = new StringBuilder();
        sb.append(_class.getName());
        sb.append('<');
        sb.append(_referencedType.toCanonical());
        sb.append('>');
        return sb.toString();
    }

    /*
    /**********************************************************
    /* Narrow/widen
    /**********************************************************
     */

    @Override
    @Deprecated // since 2.7
    protected JavaType _narrow(Class<?> subclass)
    {
        // Should we check that there is a sub-class relationship?
        return new ReferenceType(subclass, _bindings,
                _superClass, _superInterfaces, _referencedType, _anchorType,
                _valueHandler, _typeHandler, _asStatic);
    }

    /*
    /**********************************************************
    /* Public API overrides
    /**********************************************************
     */

    @Override
    public JavaType getContentType() {
        return _referencedType;
    }

    @Override
    public JavaType getReferencedType() {
        return _referencedType;
    }

    @Override
    public boolean hasContentType() {
        return true;
    }

    @Override
    public boolean isReferenceType() {
        return true;
    }

    @Override
    public StringBuilder getErasedSignature(StringBuilder sb) {
        return _classSignature(_class, sb, true);
    }
    
    @Override
    public StringBuilder getGenericSignature(StringBuilder sb)
    {
        _classSignature(_class, sb, false);
        sb.append('<');
        sb = _referencedType.getGenericSignature(sb);
        sb.append(">;");
        return sb;
    }

    /*
    /**********************************************************
    /* Extended API
    /**********************************************************
     */

    public JavaType getAnchorType() {
        return _anchorType;
    }

    /**
     * Convenience accessor that allows checking whether this is the anchor type
     * itself; if not, it must be one of supertypes that is also a {@link ReferenceType}
     */
    public boolean isAnchorType() {
        return (_anchorType == this);
    }

    /*
    /**********************************************************
    /* Standard methods
    /**********************************************************
     */

    @Override
    public String toString()
    {
        return new StringBuilder(40)
            .append("[reference type, class ")
            .append(buildCanonicalName())
            .append('<')
            .append(_referencedType)
            .append('>')
            .append(']')
            .toString();
    }

    @Override
    public boolean equals(Object o)
    {
        if (o == this) return true;
        if (o == null) return false;
        if (o.getClass() != getClass()) return false;

        ReferenceType other = (ReferenceType) o;

        if (other._class != _class) return false;
        
        // Otherwise actually mostly worry about referenced type
        return _referencedType.equals(other._referencedType);
    }
}