1 package com.fasterxml.jackson.core.util;
2
3 import java.io.*;
4
5 import com.fasterxml.jackson.core.*;
6 import com.fasterxml.jackson.core.io.SerializedString;
7
8 /**
9  * Default {@link PrettyPrinter} implementation that uses 2-space
10  * indentation with platform-default linefeeds.
11  * Usually this class is not instantiated directly, but instead
12  * method {@link JsonGenerator#useDefaultPrettyPrinter} is
13  * used, which will use an instance of this class for operation.
14  */

15 @SuppressWarnings("serial")
16 public class DefaultPrettyPrinter
17     implements PrettyPrinter, Instantiatable<DefaultPrettyPrinter>,
18         java.io.Serializable
19 {
20     private static final long serialVersionUID = 1;
21
22     /**
23      * Constant that specifies default "root-level" separator to use between
24      * root values: a single space character.
25      * 
26      * @since 2.1
27      */

28     public final static SerializedString DEFAULT_ROOT_VALUE_SEPARATOR = new SerializedString(" ");
29
30     /**
31      * Interface that defines objects that can produce indentation used
32      * to separate object entries and array values. Indentation in this
33      * context just means insertion of white space, independent of whether
34      * linefeeds are output.
35      */

36     public interface Indenter
37     {
38         void writeIndentation(JsonGenerator g, int level) throws IOException;
39
40         /**
41          * @return True if indenter is considered inline (does not add linefeeds),
42          *   false otherwise
43          */

44         boolean isInline();
45     }
46
47     // // // Config, indentation
48
49     /**
50      * By default, let's use only spaces to separate array values.
51      */

52     protected Indenter _arrayIndenter = FixedSpaceIndenter.instance;
53
54     /**
55      * By default, let's use linefeed-adding indenter for separate
56      * object entries. We'll further configure indenter to use
57      * system-specific linefeeds, and 2 spaces per level (as opposed to,
58      * say, single tabs)
59      */

60     protected Indenter _objectIndenter = DefaultIndenter.SYSTEM_LINEFEED_INSTANCE;
61
62     /**
63      * String printed between root-level values, if any.
64      */

65     protected final SerializableString _rootSeparator;
66
67     // // // Config, other white space configuration
68
69     /**
70      * By default we will add spaces around colons used to
71      * separate object fields and values.
72      * If disabled, will not use spaces around colon.
73      */

74     protected boolean _spacesInObjectEntries = true;
75
76     // // // State:
77
78     /**
79      * Number of open levels of nesting. Used to determine amount of
80      * indentation to use.
81      */

82     protected transient int _nesting;
83
84     /**
85      * @since 2.9
86      */

87     protected Separators _separators;
88
89     /**
90      * @since 2.9
91      */

92     protected String _objectFieldValueSeparatorWithSpaces;
93
94     /*
95     /**********************************************************
96     /* Life-cycle (construct, configure)
97     /**********************************************************
98     */

99
100     public DefaultPrettyPrinter() {
101         this(DEFAULT_ROOT_VALUE_SEPARATOR);
102     }
103
104     /**
105      * Constructor that specifies separator String to use between root values;
106      * if null, no separator is printed.
107      *<p>
108      * Note: simply constructs a {@link SerializedString} out of parameter,
109      * calls {@link #DefaultPrettyPrinter(SerializableString)}
110      * 
111      * @param rootSeparator
112      * 
113      * @since 2.1
114      */

115     public DefaultPrettyPrinter(String rootSeparator) {
116         this((rootSeparator == null) ? null : new SerializedString(rootSeparator));
117     }
118
119     /**
120      * Constructor that specifies separator String to use between root values;
121      * if null, no separator is printed.
122      * 
123      * @param rootSeparator
124      * 
125      * @since 2.1
126      */

127     public DefaultPrettyPrinter(SerializableString rootSeparator) {
128         _rootSeparator = rootSeparator;
129         withSeparators(DEFAULT_SEPARATORS);
130     }
131     
132     public DefaultPrettyPrinter(DefaultPrettyPrinter base) {
133         this(base, base._rootSeparator);
134     }
135
136     public DefaultPrettyPrinter(DefaultPrettyPrinter base,
137             SerializableString rootSeparator)
138     {
139         _arrayIndenter = base._arrayIndenter;
140         _objectIndenter = base._objectIndenter;
141         _spacesInObjectEntries = base._spacesInObjectEntries;
142         _nesting = base._nesting;
143
144         _separators = base._separators;
145         _objectFieldValueSeparatorWithSpaces = base._objectFieldValueSeparatorWithSpaces;
146
147         _rootSeparator = rootSeparator;
148     }
149
150     public DefaultPrettyPrinter withRootSeparator(SerializableString rootSeparator)
151     {
152         if (_rootSeparator == rootSeparator ||
153                 (rootSeparator != null && rootSeparator.equals(_rootSeparator))) {
154             return this;
155         }
156         return new DefaultPrettyPrinter(this, rootSeparator);
157     }
158
159     /**
160      * @since 2.6
161      */

162     public DefaultPrettyPrinter withRootSeparator(String rootSeparator) {
163         return withRootSeparator((rootSeparator == null) ? null : new SerializedString(rootSeparator));
164     }
165
166     public void indentArraysWith(Indenter i) {
167         _arrayIndenter = (i == null) ? NopIndenter.instance : i;
168     }
169
170     public void indentObjectsWith(Indenter i) {
171         _objectIndenter = (i == null) ? NopIndenter.instance : i;
172     }
173
174     /**
175      * @since 2.3
176      */

177     public DefaultPrettyPrinter withArrayIndenter(Indenter i) {
178         if (i == null) {
179             i = NopIndenter.instance;
180         }
181         if (_arrayIndenter == i) {
182             return this;
183         }
184         DefaultPrettyPrinter pp = new DefaultPrettyPrinter(this);
185         pp._arrayIndenter = i;
186         return pp;
187     }
188
189     /**
190      * @since 2.3
191      */

192     public DefaultPrettyPrinter withObjectIndenter(Indenter i) {
193         if (i == null) {
194             i = NopIndenter.instance;
195         }
196         if (_objectIndenter == i) {
197             return this;
198         }
199         DefaultPrettyPrinter pp = new DefaultPrettyPrinter(this);
200         pp._objectIndenter = i;
201         return pp;
202     }
203
204     /**
205      * "Mutant factory" method that will return a pretty printer instance
206      * that does use spaces inside object entries; if 'this' instance already
207      * does this, it is returned; if not, a new instance will be constructed
208      * and returned.
209      *
210      * @since 2.3
211      */

212     public DefaultPrettyPrinter withSpacesInObjectEntries() {
213         return _withSpaces(true);
214     }
215
216     /**
217      * "Mutant factory" method that will return a pretty printer instance
218      * that does not use spaces inside object entries; if 'this' instance already
219      * does this, it is returned; if not, a new instance will be constructed
220      * and returned.
221      *
222      * @since 2.3
223      */

224     public DefaultPrettyPrinter withoutSpacesInObjectEntries() {
225         return _withSpaces(false);
226     }
227
228     protected DefaultPrettyPrinter _withSpaces(boolean state)
229     {
230         if (_spacesInObjectEntries == state) {
231             return this;
232         }
233         DefaultPrettyPrinter pp = new DefaultPrettyPrinter(this);
234         pp._spacesInObjectEntries = state;
235         return pp;
236     }
237
238     /**
239      * @since 2.9
240      */

241     public DefaultPrettyPrinter withSeparators(Separators separators) {
242         _separators = separators;
243         _objectFieldValueSeparatorWithSpaces = " " + separators.getObjectFieldValueSeparator() + " ";
244         return this;
245     }
246
247     /*
248     /**********************************************************
249     /* Instantiatable impl
250     /**********************************************************
251      */

252
253     @Override
254     public DefaultPrettyPrinter createInstance() {
255         if (getClass() != DefaultPrettyPrinter.class) { // since 2.10
256             throw new IllegalStateException("Failed `createInstance()`: "+getClass().getName()
257                     +" does not override method; it has to");
258         }
259         return new DefaultPrettyPrinter(this);
260     }
261
262     /*
263     /**********************************************************
264     /* PrettyPrinter impl
265     /**********************************************************
266      */

267
268     @Override
269     public void writeRootValueSeparator(JsonGenerator g) throws IOException
270     {
271         if (_rootSeparator != null) {
272             g.writeRaw(_rootSeparator);
273         }
274     }
275
276     @Override
277     public void writeStartObject(JsonGenerator g) throws IOException
278     {
279         g.writeRaw('{');
280         if (!_objectIndenter.isInline()) {
281             ++_nesting;
282         }
283     }
284
285     @Override
286     public void beforeObjectEntries(JsonGenerator g) throws IOException
287     {
288         _objectIndenter.writeIndentation(g, _nesting);
289     }
290
291     /**
292      * Method called after an object field has been output, but
293      * before the value is output.
294      *<p>
295      * Default handling (without pretty-printing) will output a single
296      * colon to separate the two. Pretty-printer is
297      * to output a colon as well, but can surround that with other
298      * (white-space) decoration.
299      */

300     @Override
301     public void writeObjectFieldValueSeparator(JsonGenerator g) throws IOException
302     {
303         if (_spacesInObjectEntries) {
304             g.writeRaw(_objectFieldValueSeparatorWithSpaces);
305         } else {
306             g.writeRaw(_separators.getObjectFieldValueSeparator());
307         }
308     }
309
310     /**
311      * Method called after an object entry (field:value) has been completely
312      * output, and before another value is to be output.
313      *<p>
314      * Default handling (without pretty-printing) will output a single
315      * comma to separate the two. Pretty-printer is
316      * to output a comma as well, but can surround that with other
317      * (white-space) decoration.
318      */

319     @Override
320     public void writeObjectEntrySeparator(JsonGenerator g) throws IOException
321     {
322         g.writeRaw(_separators.getObjectEntrySeparator());
323         _objectIndenter.writeIndentation(g, _nesting);
324     }
325
326     @Override
327     public void writeEndObject(JsonGenerator g, int nrOfEntries) throws IOException
328     {
329         if (!_objectIndenter.isInline()) {
330             --_nesting;
331         }
332         if (nrOfEntries > 0) {
333             _objectIndenter.writeIndentation(g, _nesting);
334         } else {
335             g.writeRaw(' ');
336         }
337         g.writeRaw('}');
338     }
339
340     @Override
341     public void writeStartArray(JsonGenerator g) throws IOException
342     {
343         if (!_arrayIndenter.isInline()) {
344             ++_nesting;
345         }
346         g.writeRaw('[');
347     }
348
349     @Override
350     public void beforeArrayValues(JsonGenerator g) throws IOException {
351         _arrayIndenter.writeIndentation(g, _nesting);
352     }
353
354     /**
355      * Method called after an array value has been completely
356      * output, and before another value is to be output.
357      *<p>
358      * Default handling (without pretty-printing) will output a single
359      * comma to separate the two. Pretty-printer is
360      * to output a comma as well, but can surround that with other
361      * (white-space) decoration.
362      */

363     @Override
364     public void writeArrayValueSeparator(JsonGenerator g) throws IOException
365     {
366         g.writeRaw(_separators.getArrayValueSeparator());
367         _arrayIndenter.writeIndentation(g, _nesting);
368     }
369
370     @Override
371     public void writeEndArray(JsonGenerator g, int nrOfValues) throws IOException
372     {
373         if (!_arrayIndenter.isInline()) {
374             --_nesting;
375         }
376         if (nrOfValues > 0) {
377             _arrayIndenter.writeIndentation(g, _nesting);
378         } else {
379             g.writeRaw(' ');
380         }
381         g.writeRaw(']');
382     }
383
384     /*
385     /**********************************************************
386     /* Helper classes
387     /**********************************************************
388      */

389
390     /**
391      * Dummy implementation that adds no indentation whatsoever
392      */

393     public static class NopIndenter
394         implements Indenter, java.io.Serializable
395     {
396         public static final NopIndenter instance = new NopIndenter();
397
398         @Override
399         public void writeIndentation(JsonGenerator g, int level) throws IOException { }
400
401         @Override
402         public boolean isInline() { return true; }
403     }
404
405     /**
406      * This is a very simple indenter that only adds a
407      * single space for indentation. It is used as the default
408      * indenter for array values.
409      */

410     public static class FixedSpaceIndenter extends NopIndenter
411     {
412         public static final FixedSpaceIndenter instance = new FixedSpaceIndenter();
413
414         @Override
415         public void writeIndentation(JsonGenerator g, int level) throws IOException
416         {
417             g.writeRaw(' ');
418         }
419
420         @Override
421         public boolean isInline() { return true; }
422     }
423 }
424