aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/com/fasterxml/jackson/databind/deser/impl/PropertyBasedCreator.java
blob: e2967a8a2736fce92e060b2d81a694d2acca2a4a (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
package com.fasterxml.jackson.databind.deser.impl;

import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;

import com.fasterxml.jackson.core.JsonParser;

import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.deser.SettableBeanProperty;
import com.fasterxml.jackson.databind.deser.ValueInstantiator;
import com.fasterxml.jackson.databind.util.ClassUtil;

/**
 * Object that is used to collect arguments for non-default creator
 * (non-default-constructor, or argument-taking factory method)
 * before creator can be called.
 * Since ordering of JSON properties is not guaranteed, this may
 * require buffering of values other than ones being passed to
 * creator.
 */
public final class PropertyBasedCreator
{
    protected final ValueInstantiator _valueInstantiator;
    
    /**
     * Map that contains property objects for either constructor or factory
     * method (whichever one is null: one property for each
     * parameter for that one), keyed by logical property name
     */
    protected final HashMap<String, SettableBeanProperty> _properties;

    /**
     * If some property values must always have a non-null value (like
     * primitive types do), this array contains such default values.
     */
    protected final Object[]  _defaultValues;

    /**
     * Array that contains properties that expect value to inject, if any;
     * null if no injectable values are expected.
     * 
     * @since 1.9
     */
    protected final SettableBeanProperty[] _propertiesWithInjectables;
    
    public PropertyBasedCreator(ValueInstantiator valueInstantiator)
    {
        _valueInstantiator = valueInstantiator;
        _properties = new HashMap<String, SettableBeanProperty>();
        // [JACKSON-372]: primitive types need extra care
        Object[] defValues = null;
        SettableBeanProperty[] creatorProps = valueInstantiator.getFromObjectArguments();
        SettableBeanProperty[] propertiesWithInjectables = null;
        for (int i = 0, len = creatorProps.length; i < len; ++i) {
            SettableBeanProperty prop = creatorProps[i];
            _properties.put(prop.getName(), prop);
            if (prop.getType().isPrimitive()) {
                if (defValues == null) {
                    defValues = new Object[len];
                }
                defValues[i] = ClassUtil.defaultValue(prop.getType().getRawClass());
            }
            Object injectableValueId = prop.getInjectableValueId();
            if (injectableValueId != null) {
                if (propertiesWithInjectables == null) {
                    propertiesWithInjectables = new SettableBeanProperty[len];
                }
                propertiesWithInjectables[i] = prop;
            }
        }
        _defaultValues = defValues;
        _propertiesWithInjectables = propertiesWithInjectables;        
    }

    public Collection<SettableBeanProperty> getCreatorProperties() {
        return _properties.values();
    }
    
    public SettableBeanProperty findCreatorProperty(String name) {
        return _properties.get(name);
    }

    public void assignDeserializer(SettableBeanProperty prop, JsonDeserializer<Object> deser) {
        prop = prop.withValueDeserializer(deser);
        _properties.put(prop.getName(), prop);
    }
    
    /**
     * Method called when starting to build a bean instance.
     */
    public PropertyValueBuffer startBuilding(JsonParser jp, DeserializationContext ctxt)
    {
        PropertyValueBuffer buffer = new PropertyValueBuffer(jp, ctxt, _properties.size());
        if (_propertiesWithInjectables != null) {
            buffer.inject(_propertiesWithInjectables);
        }
        return buffer;
    }
    
    public Object build(PropertyValueBuffer buffer) throws IOException
    {
        Object bean = _valueInstantiator.createFromObjectWith(buffer.getParameters(_defaultValues));
        // Anything buffered?
        for (PropertyValue pv = buffer.buffered(); pv != null; pv = pv.next) {
            pv.assign(bean);
        }
        return bean;
    }
}