• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.fasterxml.jackson.databind.deser.impl;
2 
3 import java.lang.reflect.Member;
4 import java.util.*;
5 
6 import com.fasterxml.jackson.databind.*;
7 import com.fasterxml.jackson.databind.cfg.MapperConfig;
8 import com.fasterxml.jackson.databind.deser.SettableBeanProperty;
9 import com.fasterxml.jackson.databind.deser.ValueInstantiator;
10 import com.fasterxml.jackson.databind.deser.std.StdValueInstantiator;
11 import com.fasterxml.jackson.databind.introspect.*;
12 import com.fasterxml.jackson.databind.util.ClassUtil;
13 
14 /**
15  * Container class for storing information on creators (based on annotations,
16  * visibility), to be able to build actual instantiator later on.
17  */
18 public class CreatorCollector {
19     // Since 2.5
20     protected final static int C_DEFAULT = 0;
21     protected final static int C_STRING = 1;
22     protected final static int C_INT = 2;
23     protected final static int C_LONG = 3;
24     protected final static int C_BIG_INTEGER = 4;
25     protected final static int C_DOUBLE = 5;
26     protected final static int C_BIG_DECIMAL = 6;
27     protected final static int C_BOOLEAN = 7;
28     protected final static int C_DELEGATE = 8;
29     protected final static int C_PROPS = 9;
30     protected final static int C_ARRAY_DELEGATE = 10;
31 
32     protected final static String[] TYPE_DESCS = new String[] { "default",
33             "from-String", "from-int", "from-long", "from-big-integer", "from-double",
34             "from-big-decimal", "from-boolean", "delegate", "property-based", "array-delegate"
35     };
36 
37     // Type of bean being created
38     final protected BeanDescription _beanDesc;
39 
40     final protected boolean _canFixAccess;
41 
42     /**
43      * @since 2.7
44      */
45     final protected boolean _forceAccess;
46 
47     /**
48      * Set of creators we have collected so far
49      *
50      * @since 2.5
51      */
52     final protected AnnotatedWithParams[] _creators = new AnnotatedWithParams[11];
53 
54     /**
55      * Bitmask of creators that were explicitly marked as creators; false for
56      * auto-detected (ones included base on naming and/or visibility, not
57      * annotation)
58      *
59      * @since 2.5
60      */
61     protected int _explicitCreators = 0;
62 
63     protected boolean _hasNonDefaultCreator = false;
64 
65     // when there are injectable values along with delegate:
66     protected SettableBeanProperty[] _delegateArgs;
67 
68     protected SettableBeanProperty[] _arrayDelegateArgs;
69 
70     protected SettableBeanProperty[] _propertyBasedArgs;
71 
72     /*
73     /**********************************************************
74     /* Life-cycle
75     /**********************************************************
76      */
77 
CreatorCollector(BeanDescription beanDesc, MapperConfig<?> config)78     public CreatorCollector(BeanDescription beanDesc, MapperConfig<?> config) {
79         _beanDesc = beanDesc;
80         _canFixAccess = config.canOverrideAccessModifiers();
81         _forceAccess = config
82                 .isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS);
83     }
84 
constructValueInstantiator(DeserializationContext ctxt)85     public ValueInstantiator constructValueInstantiator(DeserializationContext ctxt)
86         throws JsonMappingException
87     {
88         final DeserializationConfig config = ctxt.getConfig();
89         final JavaType delegateType = _computeDelegateType(ctxt,
90                 _creators[C_DELEGATE], _delegateArgs);
91         final JavaType arrayDelegateType = _computeDelegateType(ctxt,
92                 _creators[C_ARRAY_DELEGATE], _arrayDelegateArgs);
93         final JavaType type = _beanDesc.getType();
94 
95         StdValueInstantiator inst = new StdValueInstantiator(config, type);
96         inst.configureFromObjectSettings(_creators[C_DEFAULT], _creators[C_DELEGATE],
97                 delegateType, _delegateArgs, _creators[C_PROPS],
98                 _propertyBasedArgs);
99         inst.configureFromArraySettings(_creators[C_ARRAY_DELEGATE],
100                 arrayDelegateType, _arrayDelegateArgs);
101         inst.configureFromStringCreator(_creators[C_STRING]);
102         inst.configureFromIntCreator(_creators[C_INT]);
103         inst.configureFromLongCreator(_creators[C_LONG]);
104         inst.configureFromBigIntegerCreator(_creators[C_BIG_INTEGER]);
105         inst.configureFromDoubleCreator(_creators[C_DOUBLE]);
106         inst.configureFromBigDecimalCreator(_creators[C_BIG_DECIMAL]);
107         inst.configureFromBooleanCreator(_creators[C_BOOLEAN]);
108         return inst;
109     }
110 
111     /*
112     /**********************************************************
113     /* Setters
114     /**********************************************************
115      */
116 
117     /**
118      * Method called to indicate the default creator: no-arguments constructor
119      * or factory method that is called to instantiate a value before populating
120      * it with data. Default creator is only used if no other creators are
121      * indicated.
122      *
123      * @param creator
124      *            Creator method; no-arguments constructor or static factory
125      *            method.
126      */
setDefaultCreator(AnnotatedWithParams creator)127     public void setDefaultCreator(AnnotatedWithParams creator) {
128         _creators[C_DEFAULT] = _fixAccess(creator);
129     }
130 
addStringCreator(AnnotatedWithParams creator, boolean explicit)131     public void addStringCreator(AnnotatedWithParams creator, boolean explicit) {
132         verifyNonDup(creator, C_STRING, explicit);
133     }
134 
addIntCreator(AnnotatedWithParams creator, boolean explicit)135     public void addIntCreator(AnnotatedWithParams creator, boolean explicit) {
136         verifyNonDup(creator, C_INT, explicit);
137     }
138 
addLongCreator(AnnotatedWithParams creator, boolean explicit)139     public void addLongCreator(AnnotatedWithParams creator, boolean explicit) {
140         verifyNonDup(creator, C_LONG, explicit);
141     }
142 
addBigIntegerCreator(AnnotatedWithParams creator, boolean explicit)143     public void addBigIntegerCreator(AnnotatedWithParams creator, boolean explicit) {
144         verifyNonDup(creator, C_BIG_INTEGER, explicit);
145     }
146 
addDoubleCreator(AnnotatedWithParams creator, boolean explicit)147     public void addDoubleCreator(AnnotatedWithParams creator, boolean explicit) {
148         verifyNonDup(creator, C_DOUBLE, explicit);
149     }
150 
addBigDecimalCreator(AnnotatedWithParams creator, boolean explicit)151     public void addBigDecimalCreator(AnnotatedWithParams creator, boolean explicit) {
152         verifyNonDup(creator, C_BIG_DECIMAL, explicit);
153     }
154 
addBooleanCreator(AnnotatedWithParams creator, boolean explicit)155     public void addBooleanCreator(AnnotatedWithParams creator, boolean explicit) {
156         verifyNonDup(creator, C_BOOLEAN, explicit);
157     }
158 
addDelegatingCreator(AnnotatedWithParams creator, boolean explicit, SettableBeanProperty[] injectables, int delegateeIndex)159     public void addDelegatingCreator(AnnotatedWithParams creator,
160             boolean explicit, SettableBeanProperty[] injectables,
161             int delegateeIndex)
162     {
163         if (creator.getParameterType(delegateeIndex).isCollectionLikeType()) {
164             if (verifyNonDup(creator, C_ARRAY_DELEGATE, explicit)) {
165                 _arrayDelegateArgs = injectables;
166             }
167         } else {
168             if (verifyNonDup(creator, C_DELEGATE, explicit)) {
169                 _delegateArgs = injectables;
170             }
171         }
172     }
173 
addPropertyCreator(AnnotatedWithParams creator, boolean explicit, SettableBeanProperty[] properties)174     public void addPropertyCreator(AnnotatedWithParams creator,
175             boolean explicit, SettableBeanProperty[] properties)
176     {
177         if (verifyNonDup(creator, C_PROPS, explicit)) {
178             // Better ensure we have no duplicate names either...
179             if (properties.length > 1) {
180                 HashMap<String, Integer> names = new HashMap<String, Integer>();
181                 for (int i = 0, len = properties.length; i < len; ++i) {
182                     String name = properties[i].getName();
183                     // Need to consider Injectables, which may not have
184                     // a name at all, and need to be skipped
185                     if (name.isEmpty() && (properties[i].getInjectableValueId() != null)) {
186                         continue;
187                     }
188                     Integer old = names.put(name, Integer.valueOf(i));
189                     if (old != null) {
190                         throw new IllegalArgumentException(String.format(
191                                 "Duplicate creator property \"%s\" (index %s vs %d) for type %s ",
192                                 name, old, i, ClassUtil.nameOf(_beanDesc.getBeanClass())));
193                     }
194                 }
195             }
196             _propertyBasedArgs = properties;
197         }
198     }
199 
200     /*
201     /**********************************************************
202     /* Accessors
203     /**********************************************************
204      */
205 
206     /**
207      * @since 2.1
208      */
hasDefaultCreator()209     public boolean hasDefaultCreator() {
210         return _creators[C_DEFAULT] != null;
211     }
212 
213     /**
214      * @since 2.6
215      */
hasDelegatingCreator()216     public boolean hasDelegatingCreator() {
217         return _creators[C_DELEGATE] != null;
218     }
219 
220     /**
221      * @since 2.6
222      */
hasPropertyBasedCreator()223     public boolean hasPropertyBasedCreator() {
224         return _creators[C_PROPS] != null;
225     }
226 
227     /*
228     /**********************************************************
229     /* Helper methods
230     /**********************************************************
231      */
232 
_computeDelegateType(DeserializationContext ctxt, AnnotatedWithParams creator, SettableBeanProperty[] delegateArgs)233     private JavaType _computeDelegateType(DeserializationContext ctxt,
234             AnnotatedWithParams creator, SettableBeanProperty[] delegateArgs)
235         throws JsonMappingException
236     {
237         if (!_hasNonDefaultCreator || (creator == null)) {
238             return null;
239         }
240         // need to find type...
241         int ix = 0;
242         if (delegateArgs != null) {
243             for (int i = 0, len = delegateArgs.length; i < len; ++i) {
244                 if (delegateArgs[i] == null) { // marker for delegate itself
245                     ix = i;
246                     break;
247                 }
248             }
249         }
250         final DeserializationConfig config = ctxt.getConfig();
251 
252         // 03-May-2018, tatu: need to check possible annotation-based
253         //   custom deserializer [databind#2012],
254         //   type refinement(s) [databind#2016].
255         JavaType baseType = creator.getParameterType(ix);
256         AnnotationIntrospector intr = config.getAnnotationIntrospector();
257         if (intr != null) {
258             AnnotatedParameter delegate = creator.getParameter(ix);
259 
260             // First: custom deserializer(s):
261             Object deserDef = intr.findDeserializer(delegate);
262             if (deserDef != null) {
263                 JsonDeserializer<Object> deser = ctxt.deserializerInstance(delegate, deserDef);
264                 baseType = baseType.withValueHandler(deser);
265             } else {
266                 // Second: type refinement(s), if no explicit deserializer was located
267                 baseType = intr.refineDeserializationType(config,
268                         delegate, baseType);
269             }
270         }
271         return baseType;
272     }
273 
_fixAccess(T member)274     private <T extends AnnotatedMember> T _fixAccess(T member) {
275         if (member != null && _canFixAccess) {
276             ClassUtil.checkAndFixAccess((Member) member.getAnnotated(),
277                     _forceAccess);
278         }
279         return member;
280     }
281 
282     /**
283      * @return True if specified Creator is to be used
284      */
verifyNonDup(AnnotatedWithParams newOne, int typeIndex, boolean explicit)285     protected boolean verifyNonDup(AnnotatedWithParams newOne, int typeIndex, boolean explicit)
286     {
287         final int mask = (1 << typeIndex);
288         _hasNonDefaultCreator = true;
289         AnnotatedWithParams oldOne = _creators[typeIndex];
290         // already had an explicitly marked one?
291         if (oldOne != null) {
292             boolean verify;
293             if ((_explicitCreators & mask) != 0) { // already had explicitly annotated, leave as-is
294                 // but skip, if new one not annotated
295                 if (!explicit) {
296                     return false;
297                 }
298                 // both explicit: verify
299                 verify = true;
300             } else {
301                 // otherwise only verify if neither explicitly annotated.
302                 verify = !explicit;
303             }
304 
305             // one more thing: ok to override in sub-class
306             if (verify && (oldOne.getClass() == newOne.getClass())) {
307                 // [databind#667]: avoid one particular class of bogus problems
308                 Class<?> oldType = oldOne.getRawParameterType(0);
309                 Class<?> newType = newOne.getRawParameterType(0);
310 
311                 if (oldType == newType) {
312                     // 13-Jul-2016, tatu: One more thing to check; since Enum classes
313                     //   always have implicitly created `valueOf()`, let's resolve in
314                     //   favor of other implicit creator (`fromString()`)
315                     if (_isEnumValueOf(newOne)) {
316                         return false; // ignore
317                     }
318                     if (_isEnumValueOf(oldOne)) {
319                         ;
320                     } else {
321                         _reportDuplicateCreator(typeIndex, explicit, oldOne, newOne);
322                     }
323                 }
324                 // otherwise, which one to choose?
325                 else if (newType.isAssignableFrom(oldType)) {
326                     // new type more generic, use old
327                     return false;
328                 } else if (oldType.isAssignableFrom(newType)) {
329                     // new type more specific, use it
330                     ;
331                 } else {
332                     // 02-May-2020, tatu: Should this only result in exception if both
333                     //   explicit? Doing so could lead to arbitrary choice between
334                     //   multiple implicit creators tho?
335                     _reportDuplicateCreator(typeIndex, explicit, oldOne, newOne);
336                 }
337             }
338         }
339         if (explicit) {
340             _explicitCreators |= mask;
341         }
342         _creators[typeIndex] = _fixAccess(newOne);
343         return true;
344     }
345 
346     // @since 2.12
_reportDuplicateCreator(int typeIndex, boolean explicit, AnnotatedWithParams oldOne, AnnotatedWithParams newOne)347     protected void _reportDuplicateCreator(int typeIndex, boolean explicit,
348             AnnotatedWithParams oldOne, AnnotatedWithParams newOne) {
349         throw new IllegalArgumentException(String.format(
350                 "Conflicting %s creators: already had %s creator %s, encountered another: %s",
351                 TYPE_DESCS[typeIndex],
352                 explicit ? "explicitly marked"
353                         : "implicitly discovered",
354                 oldOne, newOne));
355     }
356 
357     /**
358      * Helper method for recognizing `Enum.valueOf()` factory method
359      *
360      * @since 2.8.1
361      */
_isEnumValueOf(AnnotatedWithParams creator)362     protected boolean _isEnumValueOf(AnnotatedWithParams creator) {
363         return ClassUtil.isEnumType(creator.getDeclaringClass())
364                 && "valueOf".equals(creator.getName());
365     }
366 }
367