• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.fasterxml.jackson.databind.ser;
2 
3 import java.util.*;
4 
5 import com.fasterxml.jackson.databind.*;
6 import com.fasterxml.jackson.databind.introspect.AnnotatedClass;
7 import com.fasterxml.jackson.databind.introspect.AnnotatedMember;
8 import com.fasterxml.jackson.databind.ser.impl.ObjectIdWriter;
9 
10 /**
11  * Builder class used for aggregating deserialization information about
12  * a POJO, in order to build a {@link JsonSerializer} for serializing
13  * intances.
14  * Main reason for using separate builder class is that this makes it easier
15  * to make actual serializer class fully immutable.
16  */
17 public class BeanSerializerBuilder
18 {
19     private final static BeanPropertyWriter[] NO_PROPERTIES = new BeanPropertyWriter[0];
20 
21     /*
22     /**********************************************************
23     /* Basic configuration we start with
24     /**********************************************************
25      */
26 
27     final protected BeanDescription _beanDesc;
28 
29     protected SerializationConfig _config;
30 
31     /*
32     /**********************************************************
33     /* Accumulated information about properties
34     /**********************************************************
35      */
36 
37     /**
38      * Bean properties, in order of serialization
39      */
40     protected List<BeanPropertyWriter> _properties = Collections.emptyList();
41 
42     /**
43      * Optional array of filtered property writers; if null, no
44      * view-based filtering is performed.
45      */
46     protected BeanPropertyWriter[] _filteredProperties;
47 
48     /**
49      * Writer used for "any getter" properties, if any.
50      */
51     protected AnyGetterWriter _anyGetter;
52 
53     /**
54      * Id of the property filter to use for POJO, if any.
55      */
56     protected Object _filterId;
57 
58     /**
59      * Property that is used for type id (and not serialized as regular
60      * property)
61      */
62     protected AnnotatedMember _typeId;
63 
64     /**
65      * Object responsible for serializing Object Ids for the handled
66      * type, if any.
67      */
68     protected ObjectIdWriter _objectIdWriter;
69 
70     /*
71     /**********************************************************
72     /* Construction and setter methods
73     /**********************************************************
74      */
75 
BeanSerializerBuilder(BeanDescription beanDesc)76     public BeanSerializerBuilder(BeanDescription beanDesc) {
77         _beanDesc = beanDesc;
78     }
79 
80     /**
81      * Copy-constructor that may be used for sub-classing
82      */
BeanSerializerBuilder(BeanSerializerBuilder src)83     protected BeanSerializerBuilder(BeanSerializerBuilder src) {
84         _beanDesc = src._beanDesc;
85         _properties = src._properties;
86         _filteredProperties = src._filteredProperties;
87         _anyGetter = src._anyGetter;
88         _filterId = src._filterId;
89     }
90 
91     /**
92      * Initialization method called right after construction, to specify
93      * configuration to use.
94      *<p>
95      * Note: ideally should be passed in constructor, but for backwards
96      * compatibility, needed to add a setter instead
97      *
98      * @since 2.1
99      */
setConfig(SerializationConfig config)100     protected void setConfig(SerializationConfig config) {
101         _config = config;
102     }
103 
setProperties(List<BeanPropertyWriter> properties)104     public void setProperties(List<BeanPropertyWriter> properties) {
105         _properties = properties;
106     }
107 
108     /**
109      * @param properties Number and order of properties here MUST match that
110      *    of "regular" properties set earlier using {@link #setProperties(List)}; if not,
111      *    an {@link IllegalArgumentException} will be thrown
112      */
setFilteredProperties(BeanPropertyWriter[] properties)113     public void setFilteredProperties(BeanPropertyWriter[] properties) {
114         if (properties != null) {
115             if (properties.length != _properties.size()) { // as per [databind#1612]
116                 throw new IllegalArgumentException(String.format(
117                         "Trying to set %d filtered properties; must match length of non-filtered `properties` (%d)",
118                         properties.length, _properties.size()));
119             }
120         }
121         _filteredProperties = properties;
122     }
123 
setAnyGetter(AnyGetterWriter anyGetter)124     public void setAnyGetter(AnyGetterWriter anyGetter) {
125         _anyGetter = anyGetter;
126     }
127 
setFilterId(Object filterId)128     public void setFilterId(Object filterId) {
129         _filterId = filterId;
130     }
131 
setTypeId(AnnotatedMember idProp)132     public void setTypeId(AnnotatedMember idProp) {
133         // Not legal to use multiple ones...
134         if (_typeId != null) {
135             throw new IllegalArgumentException("Multiple type ids specified with "+_typeId+" and "+idProp);
136         }
137         _typeId = idProp;
138     }
139 
setObjectIdWriter(ObjectIdWriter w)140     public void setObjectIdWriter(ObjectIdWriter w) {
141         _objectIdWriter = w;
142     }
143 
144     /*
145     /**********************************************************
146     /* Accessors for things BeanSerializer cares about:
147     /* note -- likely to change between minor revisions
148     /* by new methods getting added.
149     /**********************************************************
150      */
151 
getClassInfo()152     public AnnotatedClass getClassInfo() { return _beanDesc.getClassInfo(); }
153 
getBeanDescription()154     public BeanDescription getBeanDescription() { return _beanDesc; }
155 
getProperties()156     public List<BeanPropertyWriter> getProperties() { return _properties; }
hasProperties()157     public boolean hasProperties() {
158         return (_properties != null) && (_properties.size() > 0);
159     }
160 
getFilteredProperties()161     public BeanPropertyWriter[] getFilteredProperties() { return _filteredProperties; }
162 
getAnyGetter()163     public AnyGetterWriter getAnyGetter() { return _anyGetter; }
164 
getFilterId()165     public Object getFilterId() { return _filterId; }
166 
getTypeId()167     public AnnotatedMember getTypeId() { return _typeId; }
168 
getObjectIdWriter()169     public ObjectIdWriter getObjectIdWriter() { return _objectIdWriter; }
170 
171     /*
172     /**********************************************************
173     /* Build methods for actually creating serializer instance
174     /**********************************************************
175      */
176 
177     /**
178      * Method called to create {@link BeanSerializer} instance with
179      * all accumulated information. Will construct a serializer if we
180      * have enough information, or return null if not.
181      */
build()182     public JsonSerializer<?> build()
183     {
184         // [databind#2789]: There can be a case wherein `_typeId` is used, but
185         // nothing else. Rare but has happened; so force access.
186         if (_typeId != null) {
187             if (_config.isEnabled(MapperFeature.CAN_OVERRIDE_ACCESS_MODIFIERS)) {
188                 _typeId.fixAccess(_config.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS));
189             }
190         }
191         if (_anyGetter != null) {
192             _anyGetter.fixAccess(_config);
193         }
194 
195         BeanPropertyWriter[] properties;
196         // No properties, any getter or object id writer?
197         // No real serializer; caller gets to handle
198         if (_properties == null || _properties.isEmpty()) {
199             if (_anyGetter == null && _objectIdWriter == null) {
200                 // NOTE! Caller may still call `createDummy()` later on
201                 return null;
202             }
203             properties = NO_PROPERTIES;
204         } else {
205             properties = _properties.toArray(new BeanPropertyWriter[_properties.size()]);
206             if (_config.isEnabled(MapperFeature.CAN_OVERRIDE_ACCESS_MODIFIERS)) {
207                 for (int i = 0, end = properties.length; i < end; ++i) {
208                     properties[i].fixAccess(_config);
209                 }
210             }
211         }
212         // 27-Apr-2017, tatu: Verify that filtered-properties settings are compatible
213         if (_filteredProperties != null) {
214             if (_filteredProperties.length != _properties.size()) {
215                 throw new IllegalStateException(String.format(
216 "Mismatch between `properties` size (%d), `filteredProperties` (%s): should have as many (or `null` for latter)",
217 _properties.size(), _filteredProperties.length));
218             }
219         }
220         return new BeanSerializer(_beanDesc.getType(), this,
221                 properties, _filteredProperties);
222     }
223 
224     /**
225      * Factory method for constructing an "empty" serializer; one that
226      * outputs no properties (but handles JSON objects properly, including
227      * type information)
228      */
createDummy()229     public BeanSerializer createDummy() {
230         // 20-Sep-2019, tatu: Can not skimp on passing builder  (see [databind#2077])
231         return BeanSerializer.createDummy(_beanDesc.getType(), this);
232     }
233 }
234 
235