import org.sonar.api.utils.DateUtils;
import javax.annotation.Nullable;
-
import java.io.Writer;
import java.util.Date;
import java.util.Map;
/**
* Writes JSON as a stream. This class allows plugins to not directly depend
* on the underlying JSON library.
- * <p/>
+ * <p>
* <h3>How to use</h3>
* <pre>
* StringWriter json = new StringWriter();
* .endObject()
* .close();
* </pre>
+ * </p>
+ * <p>
+ * By default, null objects are not serialized. To enable {@code null} serialization,
+ * use {@link #setSerializeNulls(boolean)}.
+ * </p>
+ * <p>
+ * By default, emptry strings are serialized. To disable empty string serialization,
+ * use {@link #setSerializeEmptys(boolean)}.
+ * </p>
*
* @since 4.2
*/
public class JsonWriter {
private final com.google.gson.stream.JsonWriter stream;
+ private boolean serializeEmptyStrings;
private JsonWriter(Writer writer) {
this.stream = new com.google.gson.stream.JsonWriter(writer);
this.stream.setSerializeNulls(false);
this.stream.setLenient(false);
+ this.serializeEmptyStrings = true;
}
// for unit testing
return this;
}
+ /**
+ * Enable/disable serialization of properties which value is an empty String.
+ */
+ public JsonWriter setSerializeEmptys(boolean serializeEmptyStrings) {
+ this.serializeEmptyStrings = serializeEmptyStrings;
+ return this;
+ }
+
/**
* Begins encoding a new array. Each call to this method must be paired with
* a call to {@link #endArray}. Output is <code>[</code>.
*/
public JsonWriter value(@Nullable String value) {
try {
- stream.value(value);
+ stream.value(serializeEmptyStrings ? value : emptyToNull(value));
return this;
} catch (Exception e) {
throw rethrow(e);
stream.nullValue();
} else {
if (value instanceof String) {
- stream.value((String) value);
+ stream.value(serializeEmptyStrings ? (String) value : emptyToNull((String) value));
} else if (value instanceof Number) {
stream.value((Number) value);
} else if (value instanceof Boolean) {
} else if (value instanceof Date) {
valueDateTime((Date) value);
} else if (value instanceof Enum) {
- stream.value(((Enum)value).name());
+ stream.value(((Enum) value).name());
} else if (value instanceof Map) {
stream.beginObject();
for (Map.Entry<Object, Object> entry : ((Map<Object, Object>) value).entrySet()) {
// stacktrace is not helpful
throw new WriterException("Fail to write JSON: " + e.getMessage());
}
+
+ @Nullable
+ private static String emptyToNull(@Nullable String value) {
+ if (value == null || value.isEmpty()) {
+ return null;
+ }
+ return value;
+ }
}
public class JsonWriterTest {
+ private static final String EMPTY_STRING = "";
+
@Rule
public ExpectedException thrown = ExpectedException.none();
expect("{\"nullNumber\":null,\"nullString\":null,\"nullNumber\":null,\"nullString\":null,\"nullDate\":null,\"nullDateTime\":null}");
}
+ @Test
+ public void serialize_empty_strings_by_default() throws Exception {
+ writer.beginObject()
+ .prop("emptyString", EMPTY_STRING)
+ .name("emptyStringAsObject").valueObject(EMPTY_STRING)
+ .endObject().close();
+ expect("{" +
+ "\"emptyString\":\"\"," +
+ "\"emptyStringAsObject\":\"\"" +
+ "}");
+ }
+
+ @Test
+ public void ignore_empty_strings_when_requested() throws Exception {
+ writer.setSerializeEmptys(false)
+ .beginObject()
+ .prop("emptyString", EMPTY_STRING)
+ .name("emptyStringAsObject").valueObject(EMPTY_STRING)
+ .endObject().close();
+ expect("{}");
+ }
+
@Test
public void escape_values() throws Exception {
writer.beginObject()