001/* 002 * SonarQube, open source software quality management tool. 003 * Copyright (C) 2008-2013 SonarSource 004 * mailto:contact AT sonarsource DOT com 005 * 006 * SonarQube is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 3 of the License, or (at your option) any later version. 010 * 011 * SonarQube is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public License 017 * along with this program; if not, write to the Free Software Foundation, 018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 019 */ 020package org.sonar.api.utils.text; 021 022import org.sonar.api.utils.DateUtils; 023 024import javax.annotation.Nullable; 025import java.io.Writer; 026import java.util.Date; 027 028/** 029 * @since 4.2 030 */ 031public class JsonWriter { 032 033 public static JsonWriter of(Writer writer) { 034 return new JsonWriter(writer); 035 } 036 037 private final com.google.gson.stream.JsonWriter stream; 038 039 private JsonWriter(Writer writer) { 040 this.stream = new com.google.gson.stream.JsonWriter(writer); 041 this.stream.setSerializeNulls(false); 042 this.stream.setLenient(false); 043 } 044 045 // for unit testing 046 JsonWriter(com.google.gson.stream.JsonWriter stream) { 047 this.stream = stream; 048 } 049 050 /** 051 * Begins encoding a new array. Each call to this method must be paired with 052 * a call to {@link #endArray}. Output is <code>[</code>. 053 * 054 * @throws org.sonar.api.utils.text.WriterException on any failure 055 */ 056 public JsonWriter beginArray() { 057 try { 058 stream.beginArray(); 059 return this; 060 } catch (Exception e) { 061 throw rethrow(e); 062 } 063 } 064 065 /** 066 * Ends encoding the current array. Output is <code>]</code>. 067 * @throws org.sonar.api.utils.text.WriterException on any failure 068 */ 069 public JsonWriter endArray() { 070 try { 071 stream.endArray(); 072 return this; 073 } catch (Exception e) { 074 throw rethrow(e); 075 } 076 } 077 078 /** 079 * Begins encoding a new object. Each call to this method must be paired 080 * with a call to {@link #endObject}. Output is <code>{</code>. 081 * @throws org.sonar.api.utils.text.WriterException on any failure 082 */ 083 public JsonWriter beginObject() { 084 try { 085 stream.beginObject(); 086 return this; 087 } catch (Exception e) { 088 throw rethrow(e); 089 } 090 } 091 092 /** 093 * Ends encoding the current object. Output is <code>}</code>. 094 * @throws org.sonar.api.utils.text.WriterException on any failure 095 */ 096 public JsonWriter endObject() { 097 try { 098 stream.endObject(); 099 return this; 100 } catch (Exception e) { 101 throw rethrow(e); 102 } 103 } 104 105 /** 106 * Encodes the property name. Output is <code>"theName":</code>. 107 * @throws org.sonar.api.utils.text.WriterException on any failure 108 */ 109 public JsonWriter name(String name) { 110 try { 111 stream.name(name); 112 return this; 113 } catch (Exception e) { 114 throw rethrow(e); 115 } 116 } 117 118 /** 119 * Encodes {@code value}. Output is <code>true</code> or <code>false</code>. 120 * @throws org.sonar.api.utils.text.WriterException on any failure 121 */ 122 public JsonWriter value(boolean value) { 123 try { 124 stream.value(value); 125 return this; 126 } catch (Exception e) { 127 throw rethrow(e); 128 } 129 } 130 131 /** 132 * @throws org.sonar.api.utils.text.WriterException on any failure 133 */ 134 public JsonWriter value(double value) { 135 try { 136 stream.value(value); 137 return this; 138 } catch (Exception e) { 139 throw rethrow(e); 140 } 141 } 142 143 /** 144 * @throws org.sonar.api.utils.text.WriterException on any failure 145 */ 146 public JsonWriter value(@Nullable String value) { 147 try { 148 stream.value(value); 149 return this; 150 } catch (Exception e) { 151 throw rethrow(e); 152 } 153 } 154 155 /** 156 * @throws org.sonar.api.utils.text.WriterException on any failure 157 */ 158 public JsonWriter valueDate(@Nullable Date value) { 159 try { 160 stream.value(value==null ? null : DateUtils.formatDate(value)); 161 return this; 162 } catch (Exception e) { 163 throw rethrow(e); 164 } 165 } 166 167 public JsonWriter valueDateTime(@Nullable Date value) { 168 try { 169 stream.value(value==null ? null : DateUtils.formatDateTime(value)); 170 return this; 171 } catch (Exception e) { 172 throw rethrow(e); 173 } 174 } 175 176 /** 177 * @throws org.sonar.api.utils.text.WriterException on any failure 178 */ 179 public JsonWriter value(long value) { 180 try { 181 stream.value(value); 182 return this; 183 } catch (Exception e) { 184 throw rethrow(e); 185 } 186 } 187 188 /** 189 * @throws org.sonar.api.utils.text.WriterException on any failure 190 */ 191 public JsonWriter value(@Nullable Number value) { 192 try { 193 stream.value(value); 194 return this; 195 } catch (Exception e) { 196 throw rethrow(e); 197 } 198 } 199 200 /** 201 * Encodes the property name and value. Output is for example <code>"theName":123</code>. 202 * @throws org.sonar.api.utils.text.WriterException on any failure 203 */ 204 public JsonWriter prop(String name, @Nullable Number value) { 205 return name(name).value(value); 206 } 207 208 /** 209 * Encodes the property name and date value (ISO format). 210 * Output is for example <code>"theDate":"2013-01-24"</code>. 211 * @throws org.sonar.api.utils.text.WriterException on any failure 212 */ 213 public JsonWriter propDate(String name, @Nullable Date value) { 214 return name(name).valueDate(value); 215 } 216 217 /** 218 * Encodes the property name and datetime value (ISO format). 219 * Output is for example <code>"theDate":"2013-01-24T13:12:45+01"</code>. 220 * @throws org.sonar.api.utils.text.WriterException on any failure 221 */ 222 public JsonWriter propDateTime(String name, @Nullable Date value) { 223 return name(name).valueDateTime(value); 224 } 225 226 /** 227 * @throws org.sonar.api.utils.text.WriterException on any failure 228 */ 229 public JsonWriter prop(String name, @Nullable String value) { 230 return name(name).value(value); 231 } 232 233 /** 234 * @throws org.sonar.api.utils.text.WriterException on any failure 235 */ 236 public JsonWriter prop(String name, boolean value) { 237 return name(name).value(value); 238 } 239 240 /** 241 * @throws org.sonar.api.utils.text.WriterException on any failure 242 */ 243 public JsonWriter prop(String name, long value) { 244 return name(name).value(value); 245 } 246 247 /** 248 * @throws org.sonar.api.utils.text.WriterException on any failure 249 */ 250 public JsonWriter prop(String name, double value) { 251 return name(name).value(value); 252 } 253 254 /** 255 * @throws org.sonar.api.utils.text.WriterException on any failure 256 */ 257 public void close() { 258 try { 259 stream.close(); 260 } catch (Exception e) { 261 throw rethrow(e); 262 } 263 } 264 265 private IllegalStateException rethrow(Exception e) { 266 // stacktrace is not helpful 267 throw new WriterException("Fail to write JSON: " + e.getMessage()); 268 } 269}