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

import java.lang.reflect.Member;
import java.util.*;


import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.deser.CreatorProperty;
import com.fasterxml.jackson.databind.deser.ValueInstantiator;
import com.fasterxml.jackson.databind.deser.std.StdValueInstantiator;
import com.fasterxml.jackson.databind.introspect.*;
import com.fasterxml.jackson.databind.type.TypeBindings;
import com.fasterxml.jackson.databind.util.ClassUtil;

/**
 * Container class for storing information on creators (based on annotations,
 * visibility), to be able to build actual instantiator later on.
 */
public class CreatorCollector
{
    /// Type of bean being created
    final BeanDescription _beanDesc;

    final boolean _canFixAccess;

    protected AnnotatedConstructor _defaultConstructor;
    
    protected AnnotatedWithParams _stringCreator, _intCreator, _longCreator;
    protected AnnotatedWithParams _doubleCreator, _booleanCreator;

    protected AnnotatedWithParams _delegateCreator;
    // when there are injectable values along with delegate:
    protected CreatorProperty[] _delegateArgs;
    
    protected AnnotatedWithParams _propertyBasedCreator;
    protected CreatorProperty[] _propertyBasedArgs = null;

    /*
    /**********************************************************
    /* Life-cycle
    /**********************************************************
     */
    
    public CreatorCollector(BeanDescription beanDesc, boolean canFixAccess)
    {
        _beanDesc = beanDesc;
        _canFixAccess = canFixAccess;
    }

    public ValueInstantiator constructValueInstantiator(DeserializationConfig config)
    {
        StdValueInstantiator inst = new StdValueInstantiator(config, _beanDesc.getType());

        JavaType delegateType;

        if (_delegateCreator == null) {
            delegateType = null;
        } else {
            // need to find type...
            int ix = 0;
            if (_delegateArgs != null) {
                for (int i = 0, len = _delegateArgs.length; i < len; ++i) {
                    if (_delegateArgs[i] == null) { // marker for delegate itself
                        ix = i;
                        break;
                    }
                }
            }
            TypeBindings bindings = _beanDesc.bindingsForBeanType();
            delegateType = bindings.resolveType(_delegateCreator.getGenericParameterType(ix));
        }
        
        inst.configureFromObjectSettings(_defaultConstructor,
                _delegateCreator, delegateType, _delegateArgs,
                _propertyBasedCreator, _propertyBasedArgs);
        inst.configureFromStringCreator(_stringCreator);
        inst.configureFromIntCreator(_intCreator);
        inst.configureFromLongCreator(_longCreator);
        inst.configureFromDoubleCreator(_doubleCreator);
        inst.configureFromBooleanCreator(_booleanCreator);
        return inst;
    }
    
    /*
    /**********************************************************
    /* Setters
    /**********************************************************
     */

    public void setDefaultConstructor(AnnotatedConstructor ctor) {
        _defaultConstructor = ctor;
    }
    
    public void addStringCreator(AnnotatedWithParams creator) {
        _stringCreator = verifyNonDup(creator, _stringCreator, "String");
    }
    public void addIntCreator(AnnotatedWithParams creator) {
        _intCreator = verifyNonDup(creator, _intCreator, "int");
    }
    public void addLongCreator(AnnotatedWithParams creator) {
        _longCreator = verifyNonDup(creator, _longCreator, "long");
    }
    public void addDoubleCreator(AnnotatedWithParams creator) {
        _doubleCreator = verifyNonDup(creator, _doubleCreator, "double");
    }
    public void addBooleanCreator(AnnotatedWithParams creator) {
        _booleanCreator = verifyNonDup(creator, _booleanCreator, "boolean");
    }

    public void addDelegatingCreator(AnnotatedWithParams creator,
            CreatorProperty[] injectables)
    {
        _delegateCreator = verifyNonDup(creator, _delegateCreator, "delegate");
        _delegateArgs = injectables;
    }
    
    public void addPropertyCreator(AnnotatedWithParams creator, CreatorProperty[] properties)
    {
        _propertyBasedCreator = verifyNonDup(creator, _propertyBasedCreator, "property-based");
        // [JACKSON-470] Better ensure we have no duplicate names either...
        if (properties.length > 1) {
            HashMap<String,Integer> names = new HashMap<String,Integer>();
            for (int i = 0, len = properties.length; i < len; ++i) {
                String name = properties[i].getName();
                Integer old = names.put(name, Integer.valueOf(i));
                if (old != null) {
                    throw new IllegalArgumentException("Duplicate creator property \""+name+"\" (index "+old+" vs "+i+")");
                }
            }
        }
        _propertyBasedArgs = properties;
    }

    /*
    /**********************************************************
    /* Helper methods
    /**********************************************************
     */

    protected AnnotatedWithParams verifyNonDup(AnnotatedWithParams newOne, AnnotatedWithParams oldOne,
            String type)
    {
        if (oldOne != null) {
            // important: ok to override factory with constructor; but not within same type, so:
            if (oldOne.getClass() == newOne.getClass()) {
                throw new IllegalArgumentException("Conflicting "+type+" creators: already had "+oldOne+", encountered "+newOne);
            }
        }
        if (_canFixAccess) {
            ClassUtil.checkAndFixAccess((Member) newOne.getAnnotated());
        }
        return newOne;
    }
}