• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.fasterxml.jackson.databind;
2 
3 import java.io.Closeable;
4 import java.io.IOException;
5 import java.util.Collection;
6 
7 import com.fasterxml.jackson.core.*;
8 import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
9 import com.fasterxml.jackson.databind.ser.DefaultSerializerProvider;
10 import com.fasterxml.jackson.databind.ser.impl.PropertySerializerMap;
11 import com.fasterxml.jackson.databind.ser.impl.TypeWrappedSerializer;
12 
13 /**
14  * Writer class similar to {@link ObjectWriter}, except that it can be used
15  * for writing sequences of values, not just a single value.
16  * The main use case is in writing very long sequences, or sequences where
17  * values are incrementally produced; cases where it would be impractical
18  * or at least inconvenient to construct a wrapper container around values
19  * (or where no JSON array is desired around values).
20  *<p>
21  * Differences from {@link ObjectWriter} include:
22  *<ul>
23  *  <li>Instances of {@link SequenceWriter} are stateful, and not thread-safe:
24  *    if sharing, external synchronization must be used.
25  *  <li>Explicit {@link #close} is needed after all values have been written
26  *     ({@link ObjectWriter} can auto-close after individual value writes)
27  *</ul>
28  *
29  * @since 2.5
30  */
31 public class SequenceWriter
32     implements Versioned, java.io.Closeable, java.io.Flushable
33 {
34     /*
35     /**********************************************************
36     /* Configuration
37     /**********************************************************
38      */
39 
40     protected final DefaultSerializerProvider _provider;
41     protected final SerializationConfig _config;
42     protected final JsonGenerator _generator;
43 
44     protected final JsonSerializer<Object> _rootSerializer;
45     protected final TypeSerializer _typeSerializer;
46 
47     protected final boolean _closeGenerator;
48     protected final boolean _cfgFlush;
49     protected final boolean _cfgCloseCloseable;
50 
51     /*
52     /**********************************************************
53     /* State
54     /**********************************************************
55      */
56 
57     /**
58      * If {@link #_rootSerializer} is not defined (no root type
59      * was used for constructing {@link ObjectWriter}), we will
60      * use simple scheme for keeping track of serializers needed.
61      * Assumption is that
62      */
63     protected PropertySerializerMap _dynamicSerializers;
64 
65     /**
66      * State flag for keeping track of need to write matching END_ARRAY,
67      * if a START_ARRAY was written during initialization
68      */
69     protected boolean _openArray;
70     protected boolean _closed;
71 
72     /*
73     /**********************************************************
74     /* Life-cycle
75     /**********************************************************
76      */
77 
SequenceWriter(DefaultSerializerProvider prov, JsonGenerator gen, boolean closeGenerator, ObjectWriter.Prefetch prefetch)78     public SequenceWriter(DefaultSerializerProvider prov, JsonGenerator gen,
79             boolean closeGenerator, ObjectWriter.Prefetch prefetch)
80         throws IOException
81     {
82         _provider = prov;
83         _generator = gen;
84         _closeGenerator = closeGenerator;
85         _rootSerializer = prefetch.getValueSerializer();
86         _typeSerializer = prefetch.getTypeSerializer();
87 
88         _config = prov.getConfig();
89         _cfgFlush = _config.isEnabled(SerializationFeature.FLUSH_AFTER_WRITE_VALUE);
90         _cfgCloseCloseable = _config.isEnabled(SerializationFeature.CLOSE_CLOSEABLE);
91         // important: need to cache "root value" serializers, to handle polymorphic
92         // types properly
93         _dynamicSerializers = PropertySerializerMap.emptyForRootValues();
94     }
95 
96     /**
97      * Internal method called by {@link ObjectWriter}: should not be called by code
98      * outside {@code jackson-databind} classes.
99      */
init(boolean wrapInArray)100     public SequenceWriter init(boolean wrapInArray) throws IOException
101     {
102         if (wrapInArray) {
103             _generator.writeStartArray();
104             _openArray = true;
105         }
106         return this;
107     }
108 
109     /*
110     /**********************************************************
111     /* Public API, basic accessors
112     /**********************************************************
113      */
114 
115     /**
116      * Method that will return version information stored in and read from jar
117      * that contains this class.
118      */
119     @Override
version()120     public Version version() {
121         return com.fasterxml.jackson.databind.cfg.PackageVersion.VERSION;
122     }
123 
124     /*
125     /**********************************************************
126     /* Public API, write operations, related
127     /**********************************************************
128      */
129 
130     /**
131      * Method for writing given value into output, as part of sequence
132      * to write. If root type was specified for {@link ObjectWriter},
133      * value must be of compatible type (same or subtype).
134      */
write(Object value)135     public SequenceWriter write(Object value) throws IOException
136     {
137         if (value == null) {
138             _provider.serializeValue(_generator, null);
139             return this;
140         }
141 
142         if (_cfgCloseCloseable && (value instanceof Closeable)) {
143             return _writeCloseableValue(value);
144         }
145         JsonSerializer<Object> ser = _rootSerializer;
146         if (ser == null) {
147             Class<?> type = value.getClass();
148             ser = _dynamicSerializers.serializerFor(type);
149             if (ser == null) {
150                 ser = _findAndAddDynamic(type);
151             }
152         }
153         _provider.serializeValue(_generator, value, null, ser);
154         if (_cfgFlush) {
155             _generator.flush();
156         }
157         return this;
158     }
159 
160     /**
161      * Method for writing given value into output, as part of sequence
162      * to write; further, full type (often generic, like {@link java.util.Map}
163      * is passed in case a new
164      * {@link JsonSerializer} needs to be fetched to handle type
165      *
166      * If root type was specified for {@link ObjectWriter},
167      * value must be of compatible type (same or subtype).
168      */
write(Object value, JavaType type)169     public SequenceWriter write(Object value, JavaType type) throws IOException
170     {
171         if (value == null) {
172             _provider.serializeValue(_generator, null);
173             return this;
174         }
175 
176         if (_cfgCloseCloseable && (value instanceof Closeable)) {
177             return _writeCloseableValue(value, type);
178         }
179         /* 15-Dec-2014, tatu: I wonder if this could become problematic. It shouldn't
180          *   really, since trying to use differently paramterized types in a sequence
181          *   is likely to run into other issues. But who knows; if it does become an
182          *   issue, may need to implement alternative, JavaType-based map.
183          */
184         JsonSerializer<Object> ser = _dynamicSerializers.serializerFor(type.getRawClass());
185         if (ser == null) {
186             ser = _findAndAddDynamic(type);
187         }
188         _provider.serializeValue(_generator, value, type, ser);
189         if (_cfgFlush) {
190             _generator.flush();
191         }
192         return this;
193     }
194 
writeAll(Object[] value)195     public SequenceWriter writeAll(Object[] value) throws IOException
196     {
197         for (int i = 0, len = value.length; i < len; ++i) {
198             write(value[i]);
199         }
200         return this;
201     }
202 
203     // NOTE: redundant wrt variant that takes Iterable, but cannot remove or even
204     // deprecate due to backwards-compatibility needs
writeAll(C container)205     public <C extends Collection<?>> SequenceWriter writeAll(C container) throws IOException {
206         for (Object value : container) {
207             write(value);
208         }
209         return this;
210     }
211 
212     /**
213      * @since 2.7
214      */
writeAll(Iterable<?> iterable)215     public SequenceWriter writeAll(Iterable<?> iterable) throws IOException
216     {
217         for (Object value : iterable) {
218             write(value);
219         }
220         return this;
221     }
222 
223     @Override
flush()224     public void flush() throws IOException {
225         if (!_closed) {
226             _generator.flush();
227         }
228     }
229 
230     @Override
close()231     public void close() throws IOException
232     {
233         if (!_closed) {
234             _closed = true;
235             if (_openArray) {
236                 _openArray = false;
237                 _generator.writeEndArray();
238             }
239             if (_closeGenerator) {
240                 _generator.close();
241             }
242         }
243     }
244 
245     /*
246     /**********************************************************
247     /* Internal helper methods, serializer lookups
248     /**********************************************************
249      */
250 
_writeCloseableValue(Object value)251     protected SequenceWriter _writeCloseableValue(Object value) throws IOException
252     {
253         Closeable toClose = (Closeable) value;
254         try {
255             JsonSerializer<Object> ser = _rootSerializer;
256             if (ser == null) {
257                 Class<?> type = value.getClass();
258                 ser = _dynamicSerializers.serializerFor(type);
259                 if (ser == null) {
260                     ser = _findAndAddDynamic(type);
261                 }
262             }
263             _provider.serializeValue(_generator, value, null, ser);
264             if (_cfgFlush) {
265                 _generator.flush();
266             }
267             Closeable tmpToClose = toClose;
268             toClose = null;
269             tmpToClose.close();
270         } finally {
271             if (toClose != null) {
272                 try {
273                     toClose.close();
274                 } catch (IOException ioe) { }
275             }
276         }
277         return this;
278     }
279 
_writeCloseableValue(Object value, JavaType type)280     protected SequenceWriter _writeCloseableValue(Object value, JavaType type) throws IOException
281     {
282         Closeable toClose = (Closeable) value;
283         try {
284             // 15-Dec-2014, tatu: As per above, could be problem that we do not pass generic type
285             JsonSerializer<Object> ser = _dynamicSerializers.serializerFor(type.getRawClass());
286             if (ser == null) {
287                 ser = _findAndAddDynamic(type);
288             }
289             _provider.serializeValue(_generator, value, type, ser);
290             if (_cfgFlush) {
291                 _generator.flush();
292             }
293             Closeable tmpToClose = toClose;
294             toClose = null;
295             tmpToClose.close();
296         } finally {
297             if (toClose != null) {
298                 try {
299                     toClose.close();
300                 } catch (IOException ioe) { }
301             }
302         }
303         return this;
304     }
305 
_findAndAddDynamic(Class<?> type)306     private final JsonSerializer<Object> _findAndAddDynamic(Class<?> type) throws JsonMappingException
307     {
308         PropertySerializerMap.SerializerAndMapResult result;
309         if (_typeSerializer == null) {
310             result = _dynamicSerializers.findAndAddRootValueSerializer(type, _provider);
311         } else {
312             result = _dynamicSerializers.addSerializer(type,
313                     new TypeWrappedSerializer(_typeSerializer, _provider.findValueSerializer(type, null)));
314         }
315         _dynamicSerializers = result.map;
316         return result.serializer;
317     }
318 
_findAndAddDynamic(JavaType type)319     private final JsonSerializer<Object> _findAndAddDynamic(JavaType type) throws JsonMappingException
320     {
321         PropertySerializerMap.SerializerAndMapResult result;
322         if (_typeSerializer == null) {
323             result = _dynamicSerializers.findAndAddRootValueSerializer(type, _provider);
324         } else {
325             result = _dynamicSerializers.addSerializer(type,
326                     new TypeWrappedSerializer(_typeSerializer, _provider.findValueSerializer(type, null)));
327         }
328         _dynamicSerializers = result.map;
329         return result.serializer;
330     }
331 }
332