blob: 5bfce603aae2cbba25806a3ab0c4156bd680aa4d [file] [log] [blame]
Tatu Salorantae4f23bb2011-12-23 00:31:35 -08001package com.fasterxml.jackson.databind.deser;
2
3import java.io.IOException;
Tatu Saloranta337feca2012-03-19 19:11:21 -07004import java.util.*;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -08005
6import com.fasterxml.jackson.core.*;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -08007import com.fasterxml.jackson.databind.*;
Tatu Saloranta2481fa42012-03-19 18:09:00 -07008import com.fasterxml.jackson.databind.deser.impl.ObjectIdReader;
9import com.fasterxml.jackson.databind.deser.impl.ReadableObjectId;
Tatu Salorantadf6302f2011-12-23 20:05:35 -080010import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080011
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080012/**
13 * Deserializer only used for abstract types used as placeholders during polymorphic
14 * type handling deserialization. If so, there is no real deserializer associated
15 * with nominal type, just {@link TypeDeserializer}; and any calls that do not
16 * pass such resolver will result in an error.
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080017 */
18public class AbstractDeserializer
19 extends JsonDeserializer<Object>
Tatu Saloranta1baf61d2012-11-05 11:53:35 -070020 implements java.io.Serializable
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080021{
Tatu Saloranta1baf61d2012-11-05 11:53:35 -070022 private static final long serialVersionUID = -3010349050434697698L;
23
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080024 protected final JavaType _baseType;
Tatu Salorantaba0470f2011-12-29 22:14:05 -080025
Tatu Saloranta2481fa42012-03-19 18:09:00 -070026 protected final ObjectIdReader _objectIdReader;
Tatu Saloranta337feca2012-03-19 19:11:21 -070027
28 protected final Map<String, SettableBeanProperty> _backRefProperties;
Tatu Salorantaa3a8d3c2013-08-26 17:46:04 -070029
Tatu Salorantaba0470f2011-12-29 22:14:05 -080030 // support for "native" types, which require special care:
31
32 protected final boolean _acceptString;
33 protected final boolean _acceptBoolean;
34 protected final boolean _acceptInt;
35 protected final boolean _acceptDouble;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080036
Tatu Saloranta337feca2012-03-19 19:11:21 -070037 public AbstractDeserializer(BeanDeserializerBuilder builder,
38 BeanDescription beanDesc, Map<String, SettableBeanProperty> backRefProps)
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080039 {
Tatu Saloranta337feca2012-03-19 19:11:21 -070040 _baseType = beanDesc.getType();
41 _objectIdReader = builder.getObjectIdReader();
42 _backRefProperties = backRefProps;
43 Class<?> cls = _baseType.getRawClass();
Tatu Salorantaba0470f2011-12-29 22:14:05 -080044 _acceptString = cls.isAssignableFrom(String.class);
45 _acceptBoolean = (cls == Boolean.TYPE) || cls.isAssignableFrom(Boolean.class);
46 _acceptInt = (cls == Integer.TYPE) || cls.isAssignableFrom(Integer.class);
47 _acceptDouble = (cls == Double.TYPE) || cls.isAssignableFrom(Double.class);
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080048 }
49
Tatu Salorantaa3a8d3c2013-08-26 17:46:04 -070050 protected AbstractDeserializer(BeanDescription beanDesc)
51 {
52 _baseType = beanDesc.getType();
53 _objectIdReader = null;
54 _backRefProperties = null;
55 Class<?> cls = _baseType.getRawClass();
56 _acceptString = cls.isAssignableFrom(String.class);
57 _acceptBoolean = (cls == Boolean.TYPE) || cls.isAssignableFrom(Boolean.class);
58 _acceptInt = (cls == Integer.TYPE) || cls.isAssignableFrom(Integer.class);
59 _acceptDouble = (cls == Double.TYPE) || cls.isAssignableFrom(Double.class);
60 }
61
62 /**
63 * Factory method used when constructing instances for non-POJO types, like
64 * {@link java.util.Map}s.
65 *
66 * @since 2.3
67 */
68 public static AbstractDeserializer constructForNonPOJO(BeanDescription beanDesc)
69 {
70 return new AbstractDeserializer(beanDesc);
71 }
72
Tatu Saloranta2481fa42012-03-19 18:09:00 -070073 /*
74 /**********************************************************
75 /* Public accessors
76 /**********************************************************
77 */
78
79 @Override
Tatu Saloranta47ac6bd2013-09-05 20:55:00 -070080 public Class<?> handledType() {
81 return _baseType.getRawClass();
82 }
83
84 @Override
Tatu Saloranta2481fa42012-03-19 18:09:00 -070085 public boolean isCachable() { return true; }
86
87 /**
88 * Overridden to return true for those instances that are
89 * handling value for which Object Identity handling is enabled
90 * (either via value type or referring property).
91 */
92 @Override
93 public ObjectIdReader getObjectIdReader() {
94 return _objectIdReader;
95 }
96
Tatu Saloranta337feca2012-03-19 19:11:21 -070097 /**
98 * Method called by <code>BeanDeserializer</code> to resolve back reference
99 * part of managed references.
100 */
Tatu Salorantac6eaf4b2013-07-04 20:25:17 -0700101 @Override
102 public SettableBeanProperty findBackReference(String logicalName) {
Tatu Saloranta337feca2012-03-19 19:11:21 -0700103 return (_backRefProperties == null) ? null : _backRefProperties.get(logicalName);
104 }
105
Tatu Saloranta2481fa42012-03-19 18:09:00 -0700106 /*
107 /**********************************************************
108 /* Deserializer implementation
109 /**********************************************************
110 */
111
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800112 @Override
113 public Object deserializeWithType(JsonParser jp, DeserializationContext ctxt,
114 TypeDeserializer typeDeserializer)
115 throws IOException, JsonProcessingException
116 {
Tatu Saloranta2481fa42012-03-19 18:09:00 -0700117 // Hmmh. One tricky question; for scalar, is it an Object Id, or "Natural" type?
Tatu Saloranta2481fa42012-03-19 18:09:00 -0700118 // for now, prefer Object Id:
119 if (_objectIdReader != null) {
120 JsonToken t = jp.getCurrentToken();
121 // should be good enough check; we only care about Strings, integral numbers:
122 if (t != null && t.isScalarValue()) {
123 return _deserializeFromObjectId(jp, ctxt);
124 }
125 }
126
Tatu Salorantaba0470f2011-12-29 22:14:05 -0800127 // First: support "natural" values (which are always serialized without type info!)
128 Object result = _deserializeIfNatural(jp, ctxt);
129 if (result != null) {
130 return result;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800131 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800132 return typeDeserializer.deserializeTypedFromObject(jp, ctxt);
133 }
134
135 @Override
136 public Object deserialize(JsonParser jp, DeserializationContext ctxt)
137 throws IOException, JsonProcessingException
138 {
Tatu Salorantaba0470f2011-12-29 22:14:05 -0800139 // This method should never be called...
Tatuf0929ac2012-01-25 16:24:40 -0800140 throw ctxt.instantiationException(_baseType.getRawClass(),
141 "abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information");
Tatu Salorantaba0470f2011-12-29 22:14:05 -0800142 }
143
Tatu Saloranta2481fa42012-03-19 18:09:00 -0700144 /*
145 /**********************************************************
146 /* Internal methods
147 /**********************************************************
148 */
149
Tatu Saloranta81c99372013-02-17 19:05:42 -0800150 @SuppressWarnings("incomplete-switch")
Tatu Salorantaba0470f2011-12-29 22:14:05 -0800151 protected Object _deserializeIfNatural(JsonParser jp, DeserializationContext ctxt)
152 throws IOException, JsonProcessingException
153 {
Tatuf0929ac2012-01-25 16:24:40 -0800154 /* As per [JACKSON-417], there is a chance we might be "natural" types
Tatu Salorantaba0470f2011-12-29 22:14:05 -0800155 * (String, Boolean, Integer, Double), which do not include any type information...
156 * Care must be taken to only return this if return type matches, however.
157 * Finally, we may have to consider possibility of custom handlers for
158 * these values: but for now this should work ok.
159 */
160 switch (jp.getCurrentToken()) {
161 case VALUE_STRING:
162 if (_acceptString) {
163 return jp.getText();
164 }
165 break;
166 case VALUE_NUMBER_INT:
167 if (_acceptInt) {
168 return jp.getIntValue();
169 }
170 break;
171
172 case VALUE_NUMBER_FLOAT:
173 if (_acceptDouble) {
174 return Double.valueOf(jp.getDoubleValue());
175 }
176 break;
177 case VALUE_TRUE:
178 if (_acceptBoolean) {
179 return Boolean.TRUE;
180 }
181 break;
182 case VALUE_FALSE:
183 if (_acceptBoolean) {
184 return Boolean.FALSE;
185 }
186 break;
187 }
188 return null;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800189 }
Tatu Saloranta2481fa42012-03-19 18:09:00 -0700190
191 /**
192 * Method called in cases where it looks like we got an Object Id
193 * to parse and use as a reference.
194 */
195 protected Object _deserializeFromObjectId(JsonParser jp, DeserializationContext ctxt)
196 throws IOException, JsonProcessingException
197 {
Tatu Saloranta9e649062013-08-05 20:29:33 -0700198 Object id = _objectIdReader.readObjectReference(jp, ctxt);
Tatu Saloranta2481fa42012-03-19 18:09:00 -0700199 ReadableObjectId roid = ctxt.findObjectId(id, _objectIdReader.generator);
200 // do we have it resolved?
201 Object pojo = roid.item;
202 if (pojo == null) { // not yet; should wait...
203 throw new IllegalStateException("Could not resolve Object Id ["+id+"] -- unresolved forward-reference?");
204 }
205 return pojo;
206 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800207}
Tatu Salorantaba0470f2011-12-29 22:14:05 -0800208