blob: a794f45c60b5c4c462d018db85582695c16837c7 [file] [log] [blame]
Tatu Salorantaf15531c2011-12-22 23:00:40 -08001/* Jackson JSON-processor.
2 *
3 * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi
4 *
5 * Licensed under the License specified in file LICENSE, included with
6 * the source code and binary code bundles.
7 * You may not use this file except in compliance with the License.
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15package com.fasterxml.jackson.core;
16
17import java.io.*;
18import java.lang.ref.SoftReference;
19import java.net.URL;
20
21import com.fasterxml.jackson.core.format.InputAccessor;
22import com.fasterxml.jackson.core.format.MatchStrength;
23import com.fasterxml.jackson.core.io.*;
24import com.fasterxml.jackson.core.json.ByteSourceJsonBootstrapper;
25import com.fasterxml.jackson.core.json.ReaderBasedJsonParser;
26import com.fasterxml.jackson.core.json.UTF8JsonGenerator;
27import com.fasterxml.jackson.core.json.WriterBasedJsonGenerator;
28import com.fasterxml.jackson.core.sym.BytesToNameCanonicalizer;
29import com.fasterxml.jackson.core.sym.CharsToNameCanonicalizer;
30import com.fasterxml.jackson.core.util.BufferRecycler;
31import com.fasterxml.jackson.core.util.VersionUtil;
32
33/**
34 * The main factory class of Jackson package, used to configure and
35 * construct reader (aka parser, {@link JsonParser})
36 * and writer (aka generator, {@link JsonGenerator})
37 * instances.
38 *<p>
39 * Factory instances are thread-safe and reusable after configuration
40 * (if any). Typically applications and services use only a single
41 * globally shared factory instance, unless they need differently
42 * configured factories. Factory reuse is important if efficiency matters;
43 * most recycling of expensive construct is done on per-factory basis.
44 *<p>
45 * Creation of a factory instance is a light-weight operation,
46 * and since there is no need for pluggable alternative implementations
47 * (as there is no "standard" JSON processor API to implement),
48 * the default constructor is used for constructing factory
49 * instances.
50 *
51 * @author Tatu Saloranta
52 */
53public class JsonFactory implements Versioned
54{
55 /**
56 * Name used to identify JSON format
57 * (and returned by {@link #getFormatName()}
58 */
59 public final static String FORMAT_NAME_JSON = "JSON";
60
61 /**
62 * Bitfield (set of flags) of all parser features that are enabled
63 * by default.
64 */
65 final static int DEFAULT_PARSER_FEATURE_FLAGS = JsonParser.Feature.collectDefaults();
66
67 /**
68 * Bitfield (set of flags) of all generator features that are enabled
69 * by default.
70 */
71 final static int DEFAULT_GENERATOR_FEATURE_FLAGS = JsonGenerator.Feature.collectDefaults();
72
73 /*
74 /**********************************************************
75 /* Buffer, symbol table management
76 /**********************************************************
77 */
78
79 /**
80 * This <code>ThreadLocal</code> contains a {@link java.lang.ref.SoftRerefence}
81 * to a {@link BufferRecycler} used to provide a low-cost
82 * buffer recycling between reader and writer instances.
83 */
84 final protected static ThreadLocal<SoftReference<BufferRecycler>> _recyclerRef
85 = new ThreadLocal<SoftReference<BufferRecycler>>();
86
87 /**
88 * Each factory comes equipped with a shared root symbol table.
89 * It should not be linked back to the original blueprint, to
90 * avoid contents from leaking between factories.
91 */
92 protected CharsToNameCanonicalizer _rootCharSymbols = CharsToNameCanonicalizer.createRoot();
93
94 /**
95 * Alternative to the basic symbol table, some stream-based
96 * parsers use different name canonicalization method.
97 *<p>
98 * TODO: should clean up this; looks messy having 2 alternatives
99 * with not very clear differences.
100 */
101 protected BytesToNameCanonicalizer _rootByteSymbols = BytesToNameCanonicalizer.createRoot();
102
103 /*
104 /**********************************************************
105 /* Configuration
106 /**********************************************************
107 */
108
109 /**
110 * Object that implements conversion functionality between
111 * Java objects and JSON content. For base JsonFactory implementation
112 * usually not set by default, but can be explicitly set.
113 * Sub-classes (like @link org.codehaus.jackson.map.MappingJsonFactory}
114 * usually provide an implementation.
115 */
116 protected ObjectCodec _objectCodec;
117
118 /**
119 * Currently enabled parser features.
120 */
121 protected int _parserFeatures = DEFAULT_PARSER_FEATURE_FLAGS;
122
123 /**
124 * Currently enabled generator features.
125 */
126 protected int _generatorFeatures = DEFAULT_GENERATOR_FEATURE_FLAGS;
127
128 /**
129 * Definition of custom character escapes to use for generators created
130 * by this factory, if any. If null, standard data format specific
131 * escapes are used.
132 */
133 protected CharacterEscapes _characterEscapes;
134
135 /**
136 * Optional helper object that may decorate input sources, to do
137 * additional processing on input during parsing.
138 */
139 protected InputDecorator _inputDecorator;
140
141 /**
142 * Optional helper object that may decorate output object, to do
143 * additional processing on output during content generation.
144 */
145 protected OutputDecorator _outputDecorator;
146
147 /*
148 /**********************************************************
149 /* Construction
150 /**********************************************************
151 */
152
153 /**
154 * Default constructor used to create factory instances.
155 * Creation of a factory instance is a light-weight operation,
156 * but it is still a good idea to reuse limited number of
157 * factory instances (and quite often just a single instance):
158 * factories are used as context for storing some reused
159 * processing objects (such as symbol tables parsers use)
160 * and this reuse only works within context of a single
161 * factory instance.
162 */
163 public JsonFactory() { this(null); }
164
165 public JsonFactory(ObjectCodec oc) { _objectCodec = oc; }
166
167 /*
168 /**********************************************************
169 /* Format detection functionality (since 1.8)
170 /**********************************************************
171 */
172
173 /**
174 * Method that returns short textual id identifying format
175 * this factory supports.
176 *<p>
177 * Note: sub-classes should override this method; default
178 * implementation will return null for all sub-classes
179 */
180 public String getFormatName()
181 {
182 /* Somewhat nasty check: since we can't make this abstract
183 * (due to backwards compatibility concerns), need to prevent
184 * format name "leakage"
185 */
186 if (getClass() == JsonFactory.class) {
187 return FORMAT_NAME_JSON;
188 }
189 return null;
190 }
191
192 public MatchStrength hasFormat(InputAccessor acc) throws IOException
193 {
194 // since we can't keep this abstract, only implement for "vanilla" instance
195 if (getClass() == JsonFactory.class) {
196 return hasJSONFormat(acc);
197 }
198 return null;
199 }
200
201 protected MatchStrength hasJSONFormat(InputAccessor acc) throws IOException
202 {
203 return ByteSourceJsonBootstrapper.hasJSONFormat(acc);
204 }
205
206 /*
207 /**********************************************************
208 /* Versioned
209 /**********************************************************
210 */
211
212 @Override
213 public Version version() {
214 // VERSION is included under impl, so can't pass this class:
215 return VersionUtil.versionFor(UTF8JsonGenerator.class);
216 }
217
218 /*
219 /**********************************************************
220 /* Configuration, parser settings
221 /**********************************************************
222 */
223
224 /**
225 * Method for enabling or disabling specified parser feature
226 * (check {@link JsonParser.Feature} for list of features)
227 */
228 public final JsonFactory configure(JsonParser.Feature f, boolean state)
229 {
230 if (state) {
231 enable(f);
232 } else {
233 disable(f);
234 }
235 return this;
236 }
237
238 /**
239 * Method for enabling specified parser feature
240 * (check {@link JsonParser.Feature} for list of features)
241 */
242 public JsonFactory enable(JsonParser.Feature f) {
243 _parserFeatures |= f.getMask();
244 return this;
245 }
246
247 /**
248 * Method for disabling specified parser features
249 * (check {@link JsonParser.Feature} for list of features)
250 */
251 public JsonFactory disable(JsonParser.Feature f) {
252 _parserFeatures &= ~f.getMask();
253 return this;
254 }
255
256 /**
257 * Checked whether specified parser feature is enabled.
258 */
259 public final boolean isEnabled(JsonParser.Feature f) {
260 return (_parserFeatures & f.getMask()) != 0;
261 }
262
263 /**
264 * Method for getting currently configured input decorator (if any;
265 * there is no default decorator).
266 */
267 public InputDecorator getInputDecorator() {
268 return _inputDecorator;
269 }
270
271 /**
272 * Method for overriding currently configured input decorator
273 */
274 public JsonFactory setInputDecorator(InputDecorator d) {
275 _inputDecorator = d;
276 return this;
277 }
278
279 /*
280 /**********************************************************
281 /* Configuration, generator settings
282 /**********************************************************
283 */
284
285 /**
286 * Method for enabling or disabling specified generator feature
287 * (check {@link JsonGenerator.Feature} for list of features)
288 */
289 public final JsonFactory configure(JsonGenerator.Feature f, boolean state) {
290 if (state) {
291 enable(f);
292 } else {
293 disable(f);
294 }
295 return this;
296 }
297
298
299 /**
300 * Method for enabling specified generator features
301 * (check {@link JsonGenerator.Feature} for list of features)
302 */
303 public JsonFactory enable(JsonGenerator.Feature f) {
304 _generatorFeatures |= f.getMask();
305 return this;
306 }
307
308 /**
309 * Method for disabling specified generator feature
310 * (check {@link JsonGenerator.Feature} for list of features)
311 */
312 public JsonFactory disable(JsonGenerator.Feature f) {
313 _generatorFeatures &= ~f.getMask();
314 return this;
315 }
316
317 /**
318 * Check whether specified generator feature is enabled.
319 */
320 public final boolean isEnabled(JsonGenerator.Feature f) {
321 return (_generatorFeatures & f.getMask()) != 0;
322 }
323
324 /**
325 * Method for accessing custom escapes factory uses for {@link JsonGenerator}s
326 * it creates.
327 */
328 public CharacterEscapes getCharacterEscapes() {
329 return _characterEscapes;
330 }
331
332 /**
333 * Method for defining custom escapes factory uses for {@link JsonGenerator}s
334 * it creates.
335 */
336 public JsonFactory setCharacterEscapes(CharacterEscapes esc) {
337 _characterEscapes = esc;
338 return this;
339 }
340
341 /**
342 * Method for getting currently configured output decorator (if any;
343 * there is no default decorator).
344 */
345 public OutputDecorator getOutputDecorator() {
346 return _outputDecorator;
347 }
348
349 /**
350 * Method for overriding currently configured output decorator
351 */
352 public JsonFactory setOutputDecorator(OutputDecorator d) {
353 _outputDecorator = d;
354 return this;
355 }
356
357 /*
358 /**********************************************************
359 /* Configuration, other
360 /**********************************************************
361 */
362
363 /**
364 * Method for associating a {@link ObjectCodec} (typically
Tatu Salorantad77350e2011-12-22 23:13:13 -0800365 * a <code>com.fasterxml.jackson.databind.ObjectMapper</code>)
366 * with this factory (and more importantly, parsers and generators
Tatu Salorantaf15531c2011-12-22 23:00:40 -0800367 * it constructs). This is needed to use data-binding methods
368 * of {@link JsonParser} and {@link JsonGenerator} instances.
369 */
370 public JsonFactory setCodec(ObjectCodec oc) {
371 _objectCodec = oc;
372 return this;
373 }
374
375 public ObjectCodec getCodec() { return _objectCodec; }
376
377 /*
378 /**********************************************************
379 /* Reader factories
380 /**********************************************************
381 */
382
383 /**
384 * Method for constructing JSON parser instance to parse
385 * contents of specified file. Encoding is auto-detected
386 * from contents according to JSON specification recommended
387 * mechanism.
388 *<p>
389 * Underlying input stream (needed for reading contents)
390 * will be <b>owned</b> (and managed, i.e. closed as need be) by
391 * the parser, since caller has no access to it.
392 *
393 * @param f File that contains JSON content to parse
394 */
395 public JsonParser createJsonParser(File f)
396 throws IOException, JsonParseException
397 {
398 // true, since we create InputStream from File
399 IOContext ctxt = _createContext(f, true);
400 InputStream in = new FileInputStream(f);
401 // [JACKSON-512]: allow wrapping with InputDecorator
402 if (_inputDecorator != null) {
403 in = _inputDecorator.decorate(ctxt, in);
404 }
405 return _createJsonParser(in, ctxt);
406 }
407
408 /**
409 * Method for constructing JSON parser instance to parse
410 * contents of resource reference by given URL.
411 * Encoding is auto-detected
412 * from contents according to JSON specification recommended
413 * mechanism.
414 *<p>
415 * Underlying input stream (needed for reading contents)
416 * will be <b>owned</b> (and managed, i.e. closed as need be) by
417 * the parser, since caller has no access to it.
418 *
419 * @param url URL pointing to resource that contains JSON content to parse
420 */
421 public JsonParser createJsonParser(URL url)
422 throws IOException, JsonParseException
423 {
424 // true, since we create InputStream from URL
425 IOContext ctxt = _createContext(url, true);
426 InputStream in = _optimizedStreamFromURL(url);
427 // [JACKSON-512]: allow wrapping with InputDecorator
428 if (_inputDecorator != null) {
429 in = _inputDecorator.decorate(ctxt, in);
430 }
431 return _createJsonParser(in, ctxt);
432 }
433
434 /**
435 * Method for constructing JSON parser instance to parse
436 * the contents accessed via specified input stream.
437 *<p>
438 * The input stream will <b>not be owned</b> by
439 * the parser, it will still be managed (i.e. closed if
440 * end-of-stream is reacher, or parser close method called)
441 * if (and only if) {@link com.fasterxml.jackson.core.JsonParser.Feature#AUTO_CLOSE_SOURCE}
442 * is enabled.
443 *<p>
444 * Note: no encoding argument is taken since it can always be
445 * auto-detected as suggested by Json RFC.
446 *
447 * @param in InputStream to use for reading JSON content to parse
448 */
449 public JsonParser createJsonParser(InputStream in)
450 throws IOException, JsonParseException
451 {
452 IOContext ctxt = _createContext(in, false);
453 // [JACKSON-512]: allow wrapping with InputDecorator
454 if (_inputDecorator != null) {
455 in = _inputDecorator.decorate(ctxt, in);
456 }
457 return _createJsonParser(in, ctxt);
458 }
459
460 /**
461 * Method for constructing parser for parsing
462 * the contents accessed via specified Reader.
463 <p>
464 * The read stream will <b>not be owned</b> by
465 * the parser, it will still be managed (i.e. closed if
466 * end-of-stream is reacher, or parser close method called)
467 * if (and only if) {@link com.fasterxml.jackson.core.JsonParser.Feature#AUTO_CLOSE_SOURCE}
468 * is enabled.
469 *<p>
470 *
471 * @param r Reader to use for reading JSON content to parse
472 */
473 public JsonParser createJsonParser(Reader r)
474 throws IOException, JsonParseException
475 {
476 // false -> we do NOT own Reader (did not create it)
477 IOContext ctxt = _createContext(r, false);
478 // [JACKSON-512]: allow wrapping with InputDecorator
479 if (_inputDecorator != null) {
480 r = _inputDecorator.decorate(ctxt, r);
481 }
482 return _createJsonParser(r, ctxt);
483 }
484
485 /**
486 * Method for constructing parser for parsing
487 * the contents of given byte array.
488 */
489 public JsonParser createJsonParser(byte[] data)
490 throws IOException, JsonParseException
491 {
492 IOContext ctxt = _createContext(data, true);
493 // [JACKSON-512]: allow wrapping with InputDecorator
494 if (_inputDecorator != null) {
495 InputStream in = _inputDecorator.decorate(ctxt, data, 0, data.length);
496 if (in != null) {
497 return _createJsonParser(in, ctxt);
498 }
499 }
500 return _createJsonParser(data, 0, data.length, ctxt);
501 }
502
503 /**
504 * Method for constructing parser for parsing
505 * the contents of given byte array.
506 *
507 * @param data Buffer that contains data to parse
508 * @param offset Offset of the first data byte within buffer
509 * @param len Length of contents to parse within buffer
510 */
511 public JsonParser createJsonParser(byte[] data, int offset, int len)
512 throws IOException, JsonParseException
513 {
514 IOContext ctxt = _createContext(data, true);
515 // [JACKSON-512]: allow wrapping with InputDecorator
516 if (_inputDecorator != null) {
517 InputStream in = _inputDecorator.decorate(ctxt, data, offset, len);
518 if (in != null) {
519 return _createJsonParser(in, ctxt);
520 }
521 }
522 return _createJsonParser(data, offset, len, ctxt);
523 }
524
525 /**
526 * Method for constructing parser for parsing
527 * contents of given String.
528 */
529 public JsonParser createJsonParser(String content)
530 throws IOException, JsonParseException
531 {
532 Reader r = new StringReader(content);
533 // true -> we own the Reader (and must close); not a big deal
534 IOContext ctxt = _createContext(r, true);
535 // [JACKSON-512]: allow wrapping with InputDecorator
536 if (_inputDecorator != null) {
537 r = _inputDecorator.decorate(ctxt, r);
538 }
539 return _createJsonParser(r, ctxt);
540 }
541
542 /*
543 /**********************************************************
544 /* Generator factories
545 /**********************************************************
546 */
547
548 /**
549 * Method for constructing JSON generator for writing JSON content
550 * using specified output stream.
551 * Encoding to use must be specified, and needs to be one of available
552 * types (as per JSON specification).
553 *<p>
554 * Underlying stream <b>is NOT owned</b> by the generator constructed,
555 * so that generator will NOT close the output stream when
556 * {@link JsonGenerator#close} is called (unless auto-closing
557 * feature,
558 * {@link com.fasterxml.jackson.core.JsonGenerator.Feature#AUTO_CLOSE_TARGET}
559 * is enabled).
560 * Using application needs to close it explicitly if this is the case.
561 *<p>
562 * Note: there are formats that use fixed encoding (like most binary data formats)
563 * and that ignore passed in encoding.
564 *
565 * @param out OutputStream to use for writing JSON content
566 * @param enc Character encoding to use
567 */
568 public JsonGenerator createJsonGenerator(OutputStream out, JsonEncoding enc)
569 throws IOException
570 {
571 // false -> we won't manage the stream unless explicitly directed to
572 IOContext ctxt = _createContext(out, false);
573 ctxt.setEncoding(enc);
574 if (enc == JsonEncoding.UTF8) {
575 // [JACKSON-512]: allow wrapping with _outputDecorator
576 if (_outputDecorator != null) {
577 out = _outputDecorator.decorate(ctxt, out);
578 }
579 return _createUTF8JsonGenerator(out, ctxt);
580 }
581 Writer w = _createWriter(out, enc, ctxt);
582 // [JACKSON-512]: allow wrapping with _outputDecorator
583 if (_outputDecorator != null) {
584 w = _outputDecorator.decorate(ctxt, w);
585 }
586 return _createJsonGenerator(w, ctxt);
587 }
588
589 /**
590 * Method for constructing JSON generator for writing JSON content
591 * using specified Writer.
592 *<p>
593 * Underlying stream <b>is NOT owned</b> by the generator constructed,
594 * so that generator will NOT close the Reader when
595 * {@link JsonGenerator#close} is called (unless auto-closing
596 * feature,
597 * {@link com.fasterxml.jackson.core.JsonGenerator.Feature#AUTO_CLOSE_TARGET} is enabled).
598 * Using application needs to close it explicitly.
599 *
600 * @param out Writer to use for writing JSON content
601 */
602 public JsonGenerator createJsonGenerator(Writer out)
603 throws IOException
604 {
605 IOContext ctxt = _createContext(out, false);
606 // [JACKSON-512]: allow wrapping with _outputDecorator
607 if (_outputDecorator != null) {
608 out = _outputDecorator.decorate(ctxt, out);
609 }
610 return _createJsonGenerator(out, ctxt);
611 }
612
613 /**
614 * Convenience method for constructing generator that uses default
615 * encoding of the format (UTF-8 for JSON and most other data formats).
616 *<p>
617 * Note: there are formats that use fixed encoding (like most binary data formats).
618 */
619 public JsonGenerator createJsonGenerator(OutputStream out) throws IOException {
620 return createJsonGenerator(out, JsonEncoding.UTF8);
621 }
622
623 /**
624 * Method for constructing JSON generator for writing JSON content
625 * to specified file, overwriting contents it might have (or creating
626 * it if such file does not yet exist).
627 * Encoding to use must be specified, and needs to be one of available
628 * types (as per JSON specification).
629 *<p>
630 * Underlying stream <b>is owned</b> by the generator constructed,
631 * i.e. generator will handle closing of file when
632 * {@link JsonGenerator#close} is called.
633 *
634 * @param f File to write contents to
635 * @param enc Character encoding to use
636 */
637 public JsonGenerator createJsonGenerator(File f, JsonEncoding enc)
638 throws IOException
639 {
640 OutputStream out = new FileOutputStream(f);
641 // true -> yes, we have to manage the stream since we created it
642 IOContext ctxt = _createContext(out, true);
643 ctxt.setEncoding(enc);
644 if (enc == JsonEncoding.UTF8) {
645 // [JACKSON-512]: allow wrapping with _outputDecorator
646 if (_outputDecorator != null) {
647 out = _outputDecorator.decorate(ctxt, out);
648 }
649 return _createUTF8JsonGenerator(out, ctxt);
650 }
651 Writer w = _createWriter(out, enc, ctxt);
652 // [JACKSON-512]: allow wrapping with _outputDecorator
653 if (_outputDecorator != null) {
654 w = _outputDecorator.decorate(ctxt, w);
655 }
656 return _createJsonGenerator(w, ctxt);
657 }
658
659 /*
660 /**********************************************************
661 /* Factory methods used by factory for creating parser instances,
662 /* overridable by sub-classes
663 /**********************************************************
664 */
665
666 /**
667 * Overridable factory method that actually instantiates desired parser
668 * given {@link InputStream} and context object.
669 *<p>
670 * This method is specifically designed to remain
671 * compatible between minor versions so that sub-classes can count
672 * on it being called as expected. That is, it is part of official
673 * interface from sub-class perspective, although not a public
674 * method available to users of factory implementations.
675 */
676 protected JsonParser _createJsonParser(InputStream in, IOContext ctxt)
677 throws IOException, JsonParseException
678 {
679 return new ByteSourceJsonBootstrapper(ctxt, in).constructParser(_parserFeatures,
680 _objectCodec, _rootByteSymbols, _rootCharSymbols);
681 }
682
683 /**
684 * Overridable factory method that actually instantiates parser
685 * using given {@link Reader} object for reading content.
686 *<p>
687 * This method is specifically designed to remain
688 * compatible between minor versions so that sub-classes can count
689 * on it being called as expected. That is, it is part of official
690 * interface from sub-class perspective, although not a public
691 * method available to users of factory implementations.
692 */
693 protected JsonParser _createJsonParser(Reader r, IOContext ctxt)
694 throws IOException, JsonParseException
695 {
696 return new ReaderBasedJsonParser(ctxt, _parserFeatures, r, _objectCodec,
697 _rootCharSymbols.makeChild(isEnabled(JsonParser.Feature.CANONICALIZE_FIELD_NAMES),
698 isEnabled(JsonParser.Feature.INTERN_FIELD_NAMES)));
699 }
700
701 /**
702 * Overridable factory method that actually instantiates parser
703 * using given {@link Reader} object for reading content
704 * passed as raw byte array.
705 *<p>
706 * This method is specifically designed to remain
707 * compatible between minor versions so that sub-classes can count
708 * on it being called as expected. That is, it is part of official
709 * interface from sub-class perspective, although not a public
710 * method available to users of factory implementations.
711 */
712 protected JsonParser _createJsonParser(byte[] data, int offset, int len, IOContext ctxt)
713 throws IOException, JsonParseException
714 {
715 return new ByteSourceJsonBootstrapper(ctxt, data, offset, len).constructParser(_parserFeatures,
716 _objectCodec, _rootByteSymbols, _rootCharSymbols);
717 }
718
719 /*
720 /**********************************************************
721 /* Factory methods used by factory for creating generator instances,
722 /* overridable by sub-classes
723 /**********************************************************
724 */
725
726 /**
727 * Overridable factory method that actually instantiates generator for
728 * given {@link Writer} and context object.
729 *<p>
730 * This method is specifically designed to remain
731 * compatible between minor versions so that sub-classes can count
732 * on it being called as expected. That is, it is part of official
733 * interface from sub-class perspective, although not a public
734 * method available to users of factory implementations.
735 */
736 protected JsonGenerator _createJsonGenerator(Writer out, IOContext ctxt)
737 throws IOException
738 {
739 WriterBasedJsonGenerator gen = new WriterBasedJsonGenerator(ctxt, _generatorFeatures, _objectCodec, out);
740 if (_characterEscapes != null) {
741 gen.setCharacterEscapes(_characterEscapes);
742 }
743 return gen;
744 }
745
746 /**
747 * Overridable factory method that actually instantiates generator for
748 * given {@link OutputStream} and context object, using UTF-8 encoding.
749 *<p>
750 * This method is specifically designed to remain
751 * compatible between minor versions so that sub-classes can count
752 * on it being called as expected. That is, it is part of official
753 * interface from sub-class perspective, although not a public
754 * method available to users of factory implementations.
755 */
756 protected JsonGenerator _createUTF8JsonGenerator(OutputStream out, IOContext ctxt)
757 throws IOException
758 {
759 UTF8JsonGenerator gen = new UTF8JsonGenerator(ctxt, _generatorFeatures, _objectCodec, out);
760 if (_characterEscapes != null) {
761 gen.setCharacterEscapes(_characterEscapes);
762 }
763 return gen;
764 }
765
766 protected Writer _createWriter(OutputStream out, JsonEncoding enc, IOContext ctxt) throws IOException
767 {
768 // note: this should not get called any more (caller checks, dispatches)
769 if (enc == JsonEncoding.UTF8) { // We have optimized writer for UTF-8
770 return new UTF8Writer(ctxt, out);
771 }
772 // not optimal, but should do unless we really care about UTF-16/32 encoding speed
773 return new OutputStreamWriter(out, enc.getJavaName());
774 }
775
776 /*
777 /**********************************************************
778 /* Internal factory methods, other
779 /**********************************************************
780 */
781
782 /**
783 * Overridable factory method that actually instantiates desired
784 * context object.
785 */
786 protected IOContext _createContext(Object srcRef, boolean resourceManaged)
787 {
788 return new IOContext(_getBufferRecycler(), srcRef, resourceManaged);
789 }
790
791 /**
792 * Method used by factory to create buffer recycler instances
793 * for parsers and generators.
794 *<p>
795 * Note: only public to give access for <code>ObjectMapper</code>
796 */
797 public BufferRecycler _getBufferRecycler()
798 {
799 SoftReference<BufferRecycler> ref = _recyclerRef.get();
800 BufferRecycler br = (ref == null) ? null : ref.get();
801
802 if (br == null) {
803 br = new BufferRecycler();
804 _recyclerRef.set(new SoftReference<BufferRecycler>(br));
805 }
806 return br;
807 }
808
809 /**
810 * Helper methods used for constructing an optimal stream for
811 * parsers to use, when input is to be read from an URL.
812 * This helps when reading file content via URL.
813 */
814 protected InputStream _optimizedStreamFromURL(URL url)
815 throws IOException
816 {
817 if ("file".equals(url.getProtocol())) {
818 /* Can not do this if the path refers
819 * to a network drive on windows. This fixes the problem;
820 * might not be needed on all platforms (NFS?), but should not
821 * matter a lot: performance penalty of extra wrapping is more
822 * relevant when accessing local file system.
823 */
824 String host = url.getHost();
825 if (host == null || host.length() == 0) {
826 return new FileInputStream(url.getPath());
827 }
828 }
829 return url.openStream();
830 }
831}