001/******************************************************************************* 002 * Copyright (c) 2015 EclipseSource. 003 * 004 * Permission is hereby granted, free of charge, to any person obtaining a copy 005 * of this software and associated documentation files (the "Software"), to deal 006 * in the Software without restriction, including without limitation the rights 007 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 008 * copies of the Software, and to permit persons to whom the Software is 009 * furnished to do so, subject to the following conditions: 010 * 011 * The above copyright notice and this permission notice shall be included in all 012 * copies or substantial portions of the Software. 013 * 014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 015 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 016 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 017 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 018 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 019 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 020 * SOFTWARE. 021 ******************************************************************************/ 022package com.restfb.json; 023 024import java.io.IOException; 025import java.io.Writer; 026import java.util.Arrays; 027import java.util.stream.Collectors; 028import java.util.stream.Stream; 029 030/** 031 * Enables human readable JSON output by inserting whitespace between values.after commas and colons. Example: 032 * 033 * <pre> 034 * jsonValue.writeTo(writer, PrettyPrint.singleLine()); 035 * </pre> 036 */ 037public class PrettyPrint implements WriterConfig { 038 039 private final char[] indentChars; 040 041 protected PrettyPrint(char[] indentChars) { 042 this.indentChars = indentChars; 043 } 044 045 /** 046 * Print every value on a separate line. Use tabs (<code>\t</code>) for indentation. 047 * 048 * @return A PrettyPrint instance for wrapped mode with tab indentation 049 */ 050 public static PrettyPrint singleLine() { 051 return new PrettyPrint(null); 052 } 053 054 /** 055 * Print every value on a separate line. Use the given number of spaces for indentation. 056 * 057 * @param number 058 * the number of spaces to use 059 * @return A PrettyPrint instance for wrapped mode with spaces indentation 060 */ 061 public static PrettyPrint indentWithSpaces(int number) { 062 if (number < 0) { 063 throw new IllegalArgumentException("number is negative"); 064 } 065 char[] chars = new char[number]; 066 Arrays.fill(chars, ' '); 067 return new PrettyPrint(chars); 068 } 069 070 /** 071 * Do not break lines, but still insert whitespace between values. 072 * 073 * @return A PrettyPrint instance for single-line mode 074 */ 075 public static PrettyPrint indentWithTabs() { 076 return new PrettyPrint(new char[] { '\t' }); 077 } 078 079 @Override 080 public JsonWriter createWriter(Writer writer) { 081 return new PrettyPrintWriter(writer, indentChars); 082 } 083 084 private static class PrettyPrintWriter extends JsonWriter { 085 086 private final char[] indentChars; 087 private int indent; 088 089 private PrettyPrintWriter(Writer writer, char[] indentChars) { 090 super(writer); 091 this.indentChars = indentChars; 092 } 093 094 @Override 095 protected void writeArrayOpen() throws IOException { 096 indent++; 097 writer.write('['); 098 writeNewLine(); 099 } 100 101 @Override 102 protected void writeArrayClose() throws IOException { 103 indent--; 104 writeNewLine(); 105 writer.write(']'); 106 } 107 108 @Override 109 protected void writeArraySeparator() throws IOException { 110 writeCommaSeparator(); 111 } 112 113 @Override 114 protected void writeObjectOpen() throws IOException { 115 indent++; 116 writer.write('{'); 117 writeNewLine(); 118 } 119 120 @Override 121 protected void writeObjectClose() throws IOException { 122 indent--; 123 writeNewLine(); 124 writer.write('}'); 125 } 126 127 @Override 128 protected void writeMemberSeparator() throws IOException { 129 writer.write(':'); 130 writer.write(' '); 131 } 132 133 @Override 134 protected void writeObjectSeparator() throws IOException { 135 writeCommaSeparator(); 136 } 137 138 protected void writeCommaSeparator() throws IOException { 139 writer.write(','); 140 if (!writeNewLine()) { 141 writer.write(' '); 142 } 143 } 144 145 private boolean writeNewLine() throws IOException { 146 if (indentChars == null) { 147 return false; 148 } 149 writer.write('\n'); 150 writer.write(Stream.generate(() -> String.valueOf(indentChars)).limit(indent).collect(Collectors.joining())); 151 return true; 152 } 153 154 } 155 156}