• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     {
writeIndentation(JsonGenerator g, int level)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          */
isInline()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 
DefaultPrettyPrinter()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      */
DefaultPrettyPrinter(String rootSeparator)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      */
DefaultPrettyPrinter(SerializableString rootSeparator)127     public DefaultPrettyPrinter(SerializableString rootSeparator) {
128         _rootSeparator = rootSeparator;
129         withSeparators(DEFAULT_SEPARATORS);
130     }
131 
DefaultPrettyPrinter(DefaultPrettyPrinter base)132     public DefaultPrettyPrinter(DefaultPrettyPrinter base) {
133         this(base, base._rootSeparator);
134     }
135 
DefaultPrettyPrinter(DefaultPrettyPrinter base, SerializableString rootSeparator)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 
withRootSeparator(SerializableString rootSeparator)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      */
withRootSeparator(String rootSeparator)162     public DefaultPrettyPrinter withRootSeparator(String rootSeparator) {
163         return withRootSeparator((rootSeparator == null) ? null : new SerializedString(rootSeparator));
164     }
165 
indentArraysWith(Indenter i)166     public void indentArraysWith(Indenter i) {
167         _arrayIndenter = (i == null) ? NopIndenter.instance : i;
168     }
169 
indentObjectsWith(Indenter i)170     public void indentObjectsWith(Indenter i) {
171         _objectIndenter = (i == null) ? NopIndenter.instance : i;
172     }
173 
174     /**
175      * @since 2.3
176      */
withArrayIndenter(Indenter i)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      */
withObjectIndenter(Indenter i)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      */
withSpacesInObjectEntries()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      */
withoutSpacesInObjectEntries()224     public DefaultPrettyPrinter withoutSpacesInObjectEntries() {
225         return _withSpaces(false);
226     }
227 
_withSpaces(boolean state)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      */
withSeparators(Separators separators)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
createInstance()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
writeRootValueSeparator(JsonGenerator g)269     public void writeRootValueSeparator(JsonGenerator g) throws IOException
270     {
271         if (_rootSeparator != null) {
272             g.writeRaw(_rootSeparator);
273         }
274     }
275 
276     @Override
writeStartObject(JsonGenerator g)277     public void writeStartObject(JsonGenerator g) throws IOException
278     {
279         g.writeRaw('{');
280         if (!_objectIndenter.isInline()) {
281             ++_nesting;
282         }
283     }
284 
285     @Override
beforeObjectEntries(JsonGenerator g)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
writeObjectFieldValueSeparator(JsonGenerator g)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
writeObjectEntrySeparator(JsonGenerator g)320     public void writeObjectEntrySeparator(JsonGenerator g) throws IOException
321     {
322         g.writeRaw(_separators.getObjectEntrySeparator());
323         _objectIndenter.writeIndentation(g, _nesting);
324     }
325 
326     @Override
writeEndObject(JsonGenerator g, int nrOfEntries)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
writeStartArray(JsonGenerator g)341     public void writeStartArray(JsonGenerator g) throws IOException
342     {
343         if (!_arrayIndenter.isInline()) {
344             ++_nesting;
345         }
346         g.writeRaw('[');
347     }
348 
349     @Override
beforeArrayValues(JsonGenerator g)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
writeArrayValueSeparator(JsonGenerator g)364     public void writeArrayValueSeparator(JsonGenerator g) throws IOException
365     {
366         g.writeRaw(_separators.getArrayValueSeparator());
367         _arrayIndenter.writeIndentation(g, _nesting);
368     }
369 
370     @Override
writeEndArray(JsonGenerator g, int nrOfValues)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
writeIndentation(JsonGenerator g, int level)399         public void writeIndentation(JsonGenerator g, int level) throws IOException { }
400 
401         @Override
isInline()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
writeIndentation(JsonGenerator g, int level)415         public void writeIndentation(JsonGenerator g, int level) throws IOException
416         {
417             g.writeRaw(' ');
418         }
419 
420         @Override
isInline()421         public boolean isInline() { return true; }
422     }
423 }
424