* Add settings for kind of newline to use * Fix amp in javadoc * Fixing link in javadoc * Doc: use JSON instead of Json Co-authored-by: Marcono1234 <Marcono1234@users.noreply.github.com> * PR Feedback: Objects.requireNonNull Co-authored-by: Marcono1234 <Marcono1234@users.noreply.github.com> * PR Feedback: $next-version$, don't hardcode Co-authored-by: Marcono1234 <Marcono1234@users.noreply.github.com> * s/testNewlineLF/testNewlineLf/ Co-authored-by: Marcono1234 <Marcono1234@users.noreply.github.com> * Implement PR feedback * Round two of review * Restore copyright year, no reason to update * Rename OS named enum values to CR and LF * Add javadoc to NewlineStyle.getValue() * Implement PR feedback, round 2 * Fix typo Co-authored-by: Marcono1234 <Marcono1234@users.noreply.github.com> * No need for line break Co-authored-by: Marcono1234 <Marcono1234@users.noreply.github.com> * Shorter, cleaner doc Co-authored-by: Marcono1234 <Marcono1234@users.noreply.github.com> * Using a FormattingStyle for pretty print * Fix Junit4 and Truth after merge from master * Implement review feedback * Double backslash in message --------- Co-authored-by: Marcono1234 <Marcono1234@users.noreply.github.com>
This commit is contained in:
parent
af21798436
commit
19f54ee6ed
98
gson/src/main/java/com/google/gson/FormattingStyle.java
Normal file
98
gson/src/main/java/com/google/gson/FormattingStyle.java
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Google Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.google.gson;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class used to control what the serialization looks like.
|
||||||
|
*
|
||||||
|
* <p>It currently defines the kind of newline to use, and the indent, but
|
||||||
|
* might add more in the future.</p>
|
||||||
|
*
|
||||||
|
* @see <a href="https://en.wikipedia.org/wiki/Newline">Wikipedia Newline article</a>
|
||||||
|
*
|
||||||
|
* @since $next-version$
|
||||||
|
*/
|
||||||
|
public class FormattingStyle {
|
||||||
|
private final String newline;
|
||||||
|
private final String indent;
|
||||||
|
|
||||||
|
static public final FormattingStyle DEFAULT =
|
||||||
|
new FormattingStyle("\n", " ");
|
||||||
|
|
||||||
|
private FormattingStyle(String newline, String indent) {
|
||||||
|
Objects.requireNonNull(newline, "newline == null");
|
||||||
|
Objects.requireNonNull(indent, "indent == null");
|
||||||
|
if (!newline.matches("[\r\n]*")) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Only combinations of \\n and \\r are allowed in newline.");
|
||||||
|
}
|
||||||
|
if (!indent.matches("[ \t]*")) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Only combinations of spaces and tabs allowed in indent.");
|
||||||
|
}
|
||||||
|
this.newline = newline;
|
||||||
|
this.indent = indent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a {@link FormattingStyle} with the specified newline setting.
|
||||||
|
*
|
||||||
|
* <p>It can be used to accommodate certain OS convention, for example
|
||||||
|
* hardcode {@code "\r"} for Linux and macos, {@code "\r\n"} for Windows, or
|
||||||
|
* call {@link java.lang.System#lineSeparator()} to match the current OS.</p>
|
||||||
|
*
|
||||||
|
* <p>Only combinations of {@code \n} and {@code \r} are allowed.</p>
|
||||||
|
*
|
||||||
|
* @param newline the string value that will be used as newline.
|
||||||
|
* @return a newly created {@link FormattingStyle}
|
||||||
|
*/
|
||||||
|
public FormattingStyle withNewline(String newline) {
|
||||||
|
return new FormattingStyle(newline, this.indent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a {@link FormattingStyle} with the specified indent string.
|
||||||
|
*
|
||||||
|
* <p>Only combinations of spaces and tabs allowed in indent.</p>
|
||||||
|
*
|
||||||
|
* @param indent the string value that will be used as indent.
|
||||||
|
* @return a newly created {@link FormattingStyle}
|
||||||
|
*/
|
||||||
|
public FormattingStyle withIndent(String indent) {
|
||||||
|
return new FormattingStyle(this.newline, indent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The string value that will be used as a newline.
|
||||||
|
*
|
||||||
|
* @return the newline value.
|
||||||
|
*/
|
||||||
|
public String getNewline() {
|
||||||
|
return this.newline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The string value that will be used as indent.
|
||||||
|
*
|
||||||
|
* @return the indent value.
|
||||||
|
*/
|
||||||
|
public String getIndent() {
|
||||||
|
return this.indent;
|
||||||
|
}
|
||||||
|
}
|
|
@ -69,8 +69,8 @@ import java.util.concurrent.atomic.AtomicLongArray;
|
||||||
*
|
*
|
||||||
* <p>You can create a Gson instance by invoking {@code new Gson()} if the default configuration
|
* <p>You can create a Gson instance by invoking {@code new Gson()} if the default configuration
|
||||||
* is all you need. You can also use {@link GsonBuilder} to build a Gson instance with various
|
* is all you need. You can also use {@link GsonBuilder} to build a Gson instance with various
|
||||||
* configuration options such as versioning support, pretty printing, custom
|
* configuration options such as versioning support, pretty printing, custom newline, custom indent,
|
||||||
* {@link JsonSerializer}s, {@link JsonDeserializer}s, and {@link InstanceCreator}s.</p>
|
* custom {@link JsonSerializer}s, {@link JsonDeserializer}s, and {@link InstanceCreator}s.</p>
|
||||||
*
|
*
|
||||||
* <p>Here is an example of how Gson is used for a simple Class:
|
* <p>Here is an example of how Gson is used for a simple Class:
|
||||||
*
|
*
|
||||||
|
@ -141,7 +141,7 @@ import java.util.concurrent.atomic.AtomicLongArray;
|
||||||
public final class Gson {
|
public final class Gson {
|
||||||
static final boolean DEFAULT_JSON_NON_EXECUTABLE = false;
|
static final boolean DEFAULT_JSON_NON_EXECUTABLE = false;
|
||||||
static final boolean DEFAULT_LENIENT = false;
|
static final boolean DEFAULT_LENIENT = false;
|
||||||
static final boolean DEFAULT_PRETTY_PRINT = false;
|
static final FormattingStyle DEFAULT_FORMATTING_STYLE = null;
|
||||||
static final boolean DEFAULT_ESCAPE_HTML = true;
|
static final boolean DEFAULT_ESCAPE_HTML = true;
|
||||||
static final boolean DEFAULT_SERIALIZE_NULLS = false;
|
static final boolean DEFAULT_SERIALIZE_NULLS = false;
|
||||||
static final boolean DEFAULT_COMPLEX_MAP_KEYS = false;
|
static final boolean DEFAULT_COMPLEX_MAP_KEYS = false;
|
||||||
|
@ -182,7 +182,7 @@ public final class Gson {
|
||||||
final boolean complexMapKeySerialization;
|
final boolean complexMapKeySerialization;
|
||||||
final boolean generateNonExecutableJson;
|
final boolean generateNonExecutableJson;
|
||||||
final boolean htmlSafe;
|
final boolean htmlSafe;
|
||||||
final boolean prettyPrinting;
|
final FormattingStyle formattingStyle;
|
||||||
final boolean lenient;
|
final boolean lenient;
|
||||||
final boolean serializeSpecialFloatingPointValues;
|
final boolean serializeSpecialFloatingPointValues;
|
||||||
final boolean useJdkUnsafe;
|
final boolean useJdkUnsafe;
|
||||||
|
@ -202,7 +202,9 @@ public final class Gson {
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>The JSON generated by <code>toJson</code> methods is in compact representation. This
|
* <li>The JSON generated by <code>toJson</code> methods is in compact representation. This
|
||||||
* means that all the unneeded white-space is removed. You can change this behavior with
|
* means that all the unneeded white-space is removed. You can change this behavior with
|
||||||
* {@link GsonBuilder#setPrettyPrinting()}. </li>
|
* {@link GsonBuilder#setPrettyPrinting()}.</li>
|
||||||
|
* <li>When the JSON generated contains more than one line, the kind of newline and indent to
|
||||||
|
* use can be configured with {@link GsonBuilder#setPrettyPrinting(FormattingStyle)}.</li>
|
||||||
* <li>The generated JSON omits all the fields that are null. Note that nulls in arrays are
|
* <li>The generated JSON omits all the fields that are null. Note that nulls in arrays are
|
||||||
* kept as is since an array is an ordered list. Moreover, if a field is not null, but its
|
* kept as is since an array is an ordered list. Moreover, if a field is not null, but its
|
||||||
* generated JSON is empty, the field is kept. You can configure Gson to serialize null values
|
* generated JSON is empty, the field is kept. You can configure Gson to serialize null values
|
||||||
|
@ -234,7 +236,7 @@ public final class Gson {
|
||||||
this(Excluder.DEFAULT, DEFAULT_FIELD_NAMING_STRATEGY,
|
this(Excluder.DEFAULT, DEFAULT_FIELD_NAMING_STRATEGY,
|
||||||
Collections.<Type, InstanceCreator<?>>emptyMap(), DEFAULT_SERIALIZE_NULLS,
|
Collections.<Type, InstanceCreator<?>>emptyMap(), DEFAULT_SERIALIZE_NULLS,
|
||||||
DEFAULT_COMPLEX_MAP_KEYS, DEFAULT_JSON_NON_EXECUTABLE, DEFAULT_ESCAPE_HTML,
|
DEFAULT_COMPLEX_MAP_KEYS, DEFAULT_JSON_NON_EXECUTABLE, DEFAULT_ESCAPE_HTML,
|
||||||
DEFAULT_PRETTY_PRINT, DEFAULT_LENIENT, DEFAULT_SPECIALIZE_FLOAT_VALUES,
|
DEFAULT_FORMATTING_STYLE, DEFAULT_LENIENT, DEFAULT_SPECIALIZE_FLOAT_VALUES,
|
||||||
DEFAULT_USE_JDK_UNSAFE,
|
DEFAULT_USE_JDK_UNSAFE,
|
||||||
LongSerializationPolicy.DEFAULT, DEFAULT_DATE_PATTERN, DateFormat.DEFAULT, DateFormat.DEFAULT,
|
LongSerializationPolicy.DEFAULT, DEFAULT_DATE_PATTERN, DateFormat.DEFAULT, DateFormat.DEFAULT,
|
||||||
Collections.<TypeAdapterFactory>emptyList(), Collections.<TypeAdapterFactory>emptyList(),
|
Collections.<TypeAdapterFactory>emptyList(), Collections.<TypeAdapterFactory>emptyList(),
|
||||||
|
@ -245,7 +247,7 @@ public final class Gson {
|
||||||
Gson(Excluder excluder, FieldNamingStrategy fieldNamingStrategy,
|
Gson(Excluder excluder, FieldNamingStrategy fieldNamingStrategy,
|
||||||
Map<Type, InstanceCreator<?>> instanceCreators, boolean serializeNulls,
|
Map<Type, InstanceCreator<?>> instanceCreators, boolean serializeNulls,
|
||||||
boolean complexMapKeySerialization, boolean generateNonExecutableGson, boolean htmlSafe,
|
boolean complexMapKeySerialization, boolean generateNonExecutableGson, boolean htmlSafe,
|
||||||
boolean prettyPrinting, boolean lenient, boolean serializeSpecialFloatingPointValues,
|
FormattingStyle formattingStyle, boolean lenient, boolean serializeSpecialFloatingPointValues,
|
||||||
boolean useJdkUnsafe,
|
boolean useJdkUnsafe,
|
||||||
LongSerializationPolicy longSerializationPolicy, String datePattern, int dateStyle,
|
LongSerializationPolicy longSerializationPolicy, String datePattern, int dateStyle,
|
||||||
int timeStyle, List<TypeAdapterFactory> builderFactories,
|
int timeStyle, List<TypeAdapterFactory> builderFactories,
|
||||||
|
@ -261,7 +263,7 @@ public final class Gson {
|
||||||
this.complexMapKeySerialization = complexMapKeySerialization;
|
this.complexMapKeySerialization = complexMapKeySerialization;
|
||||||
this.generateNonExecutableJson = generateNonExecutableGson;
|
this.generateNonExecutableJson = generateNonExecutableGson;
|
||||||
this.htmlSafe = htmlSafe;
|
this.htmlSafe = htmlSafe;
|
||||||
this.prettyPrinting = prettyPrinting;
|
this.formattingStyle = formattingStyle;
|
||||||
this.lenient = lenient;
|
this.lenient = lenient;
|
||||||
this.serializeSpecialFloatingPointValues = serializeSpecialFloatingPointValues;
|
this.serializeSpecialFloatingPointValues = serializeSpecialFloatingPointValues;
|
||||||
this.useJdkUnsafe = useJdkUnsafe;
|
this.useJdkUnsafe = useJdkUnsafe;
|
||||||
|
@ -702,7 +704,7 @@ public final class Gson {
|
||||||
* <pre>
|
* <pre>
|
||||||
* Type typeOfSrc = new TypeToken<Collection<Foo>>(){}.getType();
|
* Type typeOfSrc = new TypeToken<Collection<Foo>>(){}.getType();
|
||||||
* </pre>
|
* </pre>
|
||||||
* @return Json representation of {@code src}
|
* @return JSON representation of {@code src}.
|
||||||
* @since 1.4
|
* @since 1.4
|
||||||
*
|
*
|
||||||
* @see #toJsonTree(Object)
|
* @see #toJsonTree(Object)
|
||||||
|
@ -724,7 +726,7 @@ public final class Gson {
|
||||||
* {@link Writer}, use {@link #toJson(Object, Appendable)} instead.
|
* {@link Writer}, use {@link #toJson(Object, Appendable)} instead.
|
||||||
*
|
*
|
||||||
* @param src the object for which JSON representation is to be created
|
* @param src the object for which JSON representation is to be created
|
||||||
* @return Json representation of {@code src}.
|
* @return JSON representation of {@code src}.
|
||||||
*
|
*
|
||||||
* @see #toJson(Object, Appendable)
|
* @see #toJson(Object, Appendable)
|
||||||
* @see #toJson(Object, Type)
|
* @see #toJson(Object, Type)
|
||||||
|
@ -749,7 +751,7 @@ public final class Gson {
|
||||||
* <pre>
|
* <pre>
|
||||||
* Type typeOfSrc = new TypeToken<Collection<Foo>>(){}.getType();
|
* Type typeOfSrc = new TypeToken<Collection<Foo>>(){}.getType();
|
||||||
* </pre>
|
* </pre>
|
||||||
* @return JSON representation of {@code src}
|
* @return JSON representation of {@code src}.
|
||||||
*
|
*
|
||||||
* @see #toJson(Object, Type, Appendable)
|
* @see #toJson(Object, Type, Appendable)
|
||||||
* @see #toJson(Object)
|
* @see #toJson(Object)
|
||||||
|
@ -855,7 +857,7 @@ public final class Gson {
|
||||||
* Converts a tree of {@link JsonElement}s into its equivalent JSON representation.
|
* Converts a tree of {@link JsonElement}s into its equivalent JSON representation.
|
||||||
*
|
*
|
||||||
* @param jsonElement root of a tree of {@link JsonElement}s
|
* @param jsonElement root of a tree of {@link JsonElement}s
|
||||||
* @return JSON String representation of the tree
|
* @return JSON String representation of the tree.
|
||||||
* @since 1.4
|
* @since 1.4
|
||||||
*/
|
*/
|
||||||
public String toJson(JsonElement jsonElement) {
|
public String toJson(JsonElement jsonElement) {
|
||||||
|
@ -891,6 +893,7 @@ public final class Gson {
|
||||||
* <li>{@link GsonBuilder#serializeNulls()}</li>
|
* <li>{@link GsonBuilder#serializeNulls()}</li>
|
||||||
* <li>{@link GsonBuilder#setLenient()}</li>
|
* <li>{@link GsonBuilder#setLenient()}</li>
|
||||||
* <li>{@link GsonBuilder#setPrettyPrinting()}</li>
|
* <li>{@link GsonBuilder#setPrettyPrinting()}</li>
|
||||||
|
* <li>{@link GsonBuilder#setPrettyPrinting(FormattingStyle)}</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
public JsonWriter newJsonWriter(Writer writer) throws IOException {
|
public JsonWriter newJsonWriter(Writer writer) throws IOException {
|
||||||
|
@ -898,9 +901,7 @@ public final class Gson {
|
||||||
writer.write(JSON_NON_EXECUTABLE_PREFIX);
|
writer.write(JSON_NON_EXECUTABLE_PREFIX);
|
||||||
}
|
}
|
||||||
JsonWriter jsonWriter = new JsonWriter(writer);
|
JsonWriter jsonWriter = new JsonWriter(writer);
|
||||||
if (prettyPrinting) {
|
jsonWriter.setFormattingStyle(formattingStyle);
|
||||||
jsonWriter.setIndent(" ");
|
|
||||||
}
|
|
||||||
jsonWriter.setHtmlSafe(htmlSafe);
|
jsonWriter.setHtmlSafe(htmlSafe);
|
||||||
jsonWriter.setLenient(lenient);
|
jsonWriter.setLenient(lenient);
|
||||||
jsonWriter.setSerializeNulls(serializeNulls);
|
jsonWriter.setSerializeNulls(serializeNulls);
|
||||||
|
|
|
@ -23,7 +23,7 @@ import static com.google.gson.Gson.DEFAULT_JSON_NON_EXECUTABLE;
|
||||||
import static com.google.gson.Gson.DEFAULT_LENIENT;
|
import static com.google.gson.Gson.DEFAULT_LENIENT;
|
||||||
import static com.google.gson.Gson.DEFAULT_NUMBER_TO_NUMBER_STRATEGY;
|
import static com.google.gson.Gson.DEFAULT_NUMBER_TO_NUMBER_STRATEGY;
|
||||||
import static com.google.gson.Gson.DEFAULT_OBJECT_TO_NUMBER_STRATEGY;
|
import static com.google.gson.Gson.DEFAULT_OBJECT_TO_NUMBER_STRATEGY;
|
||||||
import static com.google.gson.Gson.DEFAULT_PRETTY_PRINT;
|
import static com.google.gson.Gson.DEFAULT_FORMATTING_STYLE;
|
||||||
import static com.google.gson.Gson.DEFAULT_SERIALIZE_NULLS;
|
import static com.google.gson.Gson.DEFAULT_SERIALIZE_NULLS;
|
||||||
import static com.google.gson.Gson.DEFAULT_SPECIALIZE_FLOAT_VALUES;
|
import static com.google.gson.Gson.DEFAULT_SPECIALIZE_FLOAT_VALUES;
|
||||||
import static com.google.gson.Gson.DEFAULT_USE_JDK_UNSAFE;
|
import static com.google.gson.Gson.DEFAULT_USE_JDK_UNSAFE;
|
||||||
|
@ -98,7 +98,7 @@ public final class GsonBuilder {
|
||||||
private boolean complexMapKeySerialization = DEFAULT_COMPLEX_MAP_KEYS;
|
private boolean complexMapKeySerialization = DEFAULT_COMPLEX_MAP_KEYS;
|
||||||
private boolean serializeSpecialFloatingPointValues = DEFAULT_SPECIALIZE_FLOAT_VALUES;
|
private boolean serializeSpecialFloatingPointValues = DEFAULT_SPECIALIZE_FLOAT_VALUES;
|
||||||
private boolean escapeHtmlChars = DEFAULT_ESCAPE_HTML;
|
private boolean escapeHtmlChars = DEFAULT_ESCAPE_HTML;
|
||||||
private boolean prettyPrinting = DEFAULT_PRETTY_PRINT;
|
private FormattingStyle formattingStyle = DEFAULT_FORMATTING_STYLE;
|
||||||
private boolean generateNonExecutableJson = DEFAULT_JSON_NON_EXECUTABLE;
|
private boolean generateNonExecutableJson = DEFAULT_JSON_NON_EXECUTABLE;
|
||||||
private boolean lenient = DEFAULT_LENIENT;
|
private boolean lenient = DEFAULT_LENIENT;
|
||||||
private boolean useJdkUnsafe = DEFAULT_USE_JDK_UNSAFE;
|
private boolean useJdkUnsafe = DEFAULT_USE_JDK_UNSAFE;
|
||||||
|
@ -129,7 +129,7 @@ public final class GsonBuilder {
|
||||||
this.complexMapKeySerialization = gson.complexMapKeySerialization;
|
this.complexMapKeySerialization = gson.complexMapKeySerialization;
|
||||||
this.generateNonExecutableJson = gson.generateNonExecutableJson;
|
this.generateNonExecutableJson = gson.generateNonExecutableJson;
|
||||||
this.escapeHtmlChars = gson.htmlSafe;
|
this.escapeHtmlChars = gson.htmlSafe;
|
||||||
this.prettyPrinting = gson.prettyPrinting;
|
this.formattingStyle = gson.formattingStyle;
|
||||||
this.lenient = gson.lenient;
|
this.lenient = gson.lenient;
|
||||||
this.serializeSpecialFloatingPointValues = gson.serializeSpecialFloatingPointValues;
|
this.serializeSpecialFloatingPointValues = gson.serializeSpecialFloatingPointValues;
|
||||||
this.longSerializationPolicy = gson.longSerializationPolicy;
|
this.longSerializationPolicy = gson.longSerializationPolicy;
|
||||||
|
@ -478,13 +478,26 @@ public final class GsonBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures Gson to output Json that fits in a page for pretty printing. This option only
|
* Configures Gson to output JSON that fits in a page for pretty printing. This option only
|
||||||
* affects Json serialization.
|
* affects JSON serialization.
|
||||||
*
|
*
|
||||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||||
*/
|
*/
|
||||||
public GsonBuilder setPrettyPrinting() {
|
public GsonBuilder setPrettyPrinting() {
|
||||||
prettyPrinting = true;
|
return setPrettyPrinting(FormattingStyle.DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures Gson to output JSON that uses a certain kind of formatting stile (for example newline and indent).
|
||||||
|
* This option only affects JSON serialization.
|
||||||
|
*
|
||||||
|
* <p>Has no effect if the serialized format is a single line.</p>
|
||||||
|
*
|
||||||
|
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||||
|
* @since $next-version$
|
||||||
|
*/
|
||||||
|
public GsonBuilder setPrettyPrinting(FormattingStyle formattingStyle) {
|
||||||
|
this.formattingStyle = formattingStyle;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -761,7 +774,7 @@ public final class GsonBuilder {
|
||||||
|
|
||||||
return new Gson(excluder, fieldNamingPolicy, new HashMap<>(instanceCreators),
|
return new Gson(excluder, fieldNamingPolicy, new HashMap<>(instanceCreators),
|
||||||
serializeNulls, complexMapKeySerialization,
|
serializeNulls, complexMapKeySerialization,
|
||||||
generateNonExecutableJson, escapeHtmlChars, prettyPrinting, lenient,
|
generateNonExecutableJson, escapeHtmlChars, formattingStyle, lenient,
|
||||||
serializeSpecialFloatingPointValues, useJdkUnsafe, longSerializationPolicy,
|
serializeSpecialFloatingPointValues, useJdkUnsafe, longSerializationPolicy,
|
||||||
datePattern, dateStyle, timeStyle, new ArrayList<>(this.factories),
|
datePattern, dateStyle, timeStyle, new ArrayList<>(this.factories),
|
||||||
new ArrayList<>(this.hierarchyFactories), factories,
|
new ArrayList<>(this.hierarchyFactories), factories,
|
||||||
|
|
|
@ -36,6 +36,8 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import com.google.gson.FormattingStyle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes a JSON (<a href="http://www.ietf.org/rfc/rfc7159.txt">RFC 7159</a>)
|
* Writes a JSON (<a href="http://www.ietf.org/rfc/rfc7159.txt">RFC 7159</a>)
|
||||||
* encoded value to a stream, one token at a time. The stream includes both
|
* encoded value to a stream, one token at a time. The stream includes both
|
||||||
|
@ -180,10 +182,9 @@ public class JsonWriter implements Closeable, Flushable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A string containing a full set of spaces for a single level of
|
* The settings used for pretty printing, or null for no pretty printing.
|
||||||
* indentation, or null for no pretty printing.
|
|
||||||
*/
|
*/
|
||||||
private String indent;
|
private FormattingStyle formattingStyle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name/value separator; either ":" or ": ".
|
* The name/value separator; either ":" or ": ".
|
||||||
|
@ -217,14 +218,44 @@ public class JsonWriter implements Closeable, Flushable {
|
||||||
*/
|
*/
|
||||||
public final void setIndent(String indent) {
|
public final void setIndent(String indent) {
|
||||||
if (indent.length() == 0) {
|
if (indent.length() == 0) {
|
||||||
this.indent = null;
|
setFormattingStyle(null);
|
||||||
|
} else {
|
||||||
|
setFormattingStyle(FormattingStyle.DEFAULT.withIndent(indent));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the pretty printing style to be used in the encoded document.
|
||||||
|
* No pretty printing if null.
|
||||||
|
*
|
||||||
|
* <p>Sets the various attributes to be used in the encoded document.
|
||||||
|
* For example the indentation string to be repeated for each level of indentation.
|
||||||
|
* Or the newline style, to accommodate various OS styles.</p>
|
||||||
|
*
|
||||||
|
* <p>Has no effect if the serialized format is a single line.</p>
|
||||||
|
*
|
||||||
|
* @param formattingStyle the style used for pretty printing, no pretty printing if null.
|
||||||
|
* @since $next-version$
|
||||||
|
*/
|
||||||
|
public final void setFormattingStyle(FormattingStyle formattingStyle) {
|
||||||
|
this.formattingStyle = formattingStyle;
|
||||||
|
if (formattingStyle == null) {
|
||||||
this.separator = ":";
|
this.separator = ":";
|
||||||
} else {
|
} else {
|
||||||
this.indent = indent;
|
|
||||||
this.separator = ": ";
|
this.separator = ": ";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the pretty printing style used by this writer.
|
||||||
|
*
|
||||||
|
* @return the FormattingStyle that will be used.
|
||||||
|
* @since $next-version$
|
||||||
|
*/
|
||||||
|
public final FormattingStyle getFormattingStyle() {
|
||||||
|
return formattingStyle;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure this writer to relax its syntax rules. By default, this writer
|
* Configure this writer to relax its syntax rules. By default, this writer
|
||||||
* only emits well-formed JSON as specified by <a
|
* only emits well-formed JSON as specified by <a
|
||||||
|
@ -645,13 +676,13 @@ public class JsonWriter implements Closeable, Flushable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void newline() throws IOException {
|
private void newline() throws IOException {
|
||||||
if (indent == null) {
|
if (formattingStyle == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
out.write('\n');
|
out.write(formattingStyle.getNewline());
|
||||||
for (int i = 1, size = stackSize; i < size; i++) {
|
for (int i = 1, size = stackSize; i < size; i++) {
|
||||||
out.write(indent);
|
out.write(formattingStyle.getIndent());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,8 @@ public final class GsonTest {
|
||||||
public void testOverridesDefaultExcluder() {
|
public void testOverridesDefaultExcluder() {
|
||||||
Gson gson = new Gson(CUSTOM_EXCLUDER, CUSTOM_FIELD_NAMING_STRATEGY,
|
Gson gson = new Gson(CUSTOM_EXCLUDER, CUSTOM_FIELD_NAMING_STRATEGY,
|
||||||
new HashMap<Type, InstanceCreator<?>>(), true, false, true, false,
|
new HashMap<Type, InstanceCreator<?>>(), true, false, true, false,
|
||||||
true, true, false, true, LongSerializationPolicy.DEFAULT, null, DateFormat.DEFAULT,
|
FormattingStyle.DEFAULT, true, false, true,
|
||||||
|
LongSerializationPolicy.DEFAULT, null, DateFormat.DEFAULT,
|
||||||
DateFormat.DEFAULT, new ArrayList<TypeAdapterFactory>(),
|
DateFormat.DEFAULT, new ArrayList<TypeAdapterFactory>(),
|
||||||
new ArrayList<TypeAdapterFactory>(), new ArrayList<TypeAdapterFactory>(),
|
new ArrayList<TypeAdapterFactory>(), new ArrayList<TypeAdapterFactory>(),
|
||||||
CUSTOM_OBJECT_TO_NUMBER_STRATEGY, CUSTOM_NUMBER_TO_NUMBER_STRATEGY,
|
CUSTOM_OBJECT_TO_NUMBER_STRATEGY, CUSTOM_NUMBER_TO_NUMBER_STRATEGY,
|
||||||
|
@ -79,7 +80,8 @@ public final class GsonTest {
|
||||||
public void testClonedTypeAdapterFactoryListsAreIndependent() {
|
public void testClonedTypeAdapterFactoryListsAreIndependent() {
|
||||||
Gson original = new Gson(CUSTOM_EXCLUDER, CUSTOM_FIELD_NAMING_STRATEGY,
|
Gson original = new Gson(CUSTOM_EXCLUDER, CUSTOM_FIELD_NAMING_STRATEGY,
|
||||||
new HashMap<Type, InstanceCreator<?>>(), true, false, true, false,
|
new HashMap<Type, InstanceCreator<?>>(), true, false, true, false,
|
||||||
true, true, false, true, LongSerializationPolicy.DEFAULT, null, DateFormat.DEFAULT,
|
FormattingStyle.DEFAULT, true, false, true,
|
||||||
|
LongSerializationPolicy.DEFAULT, null, DateFormat.DEFAULT,
|
||||||
DateFormat.DEFAULT, new ArrayList<TypeAdapterFactory>(),
|
DateFormat.DEFAULT, new ArrayList<TypeAdapterFactory>(),
|
||||||
new ArrayList<TypeAdapterFactory>(), new ArrayList<TypeAdapterFactory>(),
|
new ArrayList<TypeAdapterFactory>(), new ArrayList<TypeAdapterFactory>(),
|
||||||
CUSTOM_OBJECT_TO_NUMBER_STRATEGY, CUSTOM_NUMBER_TO_NUMBER_STRATEGY,
|
CUSTOM_OBJECT_TO_NUMBER_STRATEGY, CUSTOM_NUMBER_TO_NUMBER_STRATEGY,
|
||||||
|
|
|
@ -0,0 +1,152 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Google Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.google.gson.functional;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import com.google.gson.FormattingStyle;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.JUnit4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Functional tests for formatting styles.
|
||||||
|
*
|
||||||
|
* @author Mihai Nita
|
||||||
|
*/
|
||||||
|
@RunWith(JUnit4.class)
|
||||||
|
public class FormattingStyleTest {
|
||||||
|
|
||||||
|
private static final String[] INPUT = {"v1", "v2"};
|
||||||
|
private static final String EXPECTED = "[<EOL><INDENT>\"v1\",<EOL><INDENT>\"v2\"<EOL>]";
|
||||||
|
private static final String EXPECTED_OS = buildExpected(System.lineSeparator(), " ");
|
||||||
|
private static final String EXPECTED_CR = buildExpected("\r", " ");
|
||||||
|
private static final String EXPECTED_LF = buildExpected("\n", " ");
|
||||||
|
private static final String EXPECTED_CRLF = buildExpected("\r\n", " ");
|
||||||
|
|
||||||
|
// Various valid strings that can be used for newline and indent
|
||||||
|
private static final String[] TEST_NEWLINES = {
|
||||||
|
"", "\r", "\n", "\r\n", "\n\r\r\n", System.lineSeparator()
|
||||||
|
};
|
||||||
|
private static final String[] TEST_INDENTS = {
|
||||||
|
"", " ", " ", " ", "\t", " \t \t"
|
||||||
|
};
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDefault() {
|
||||||
|
Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||||
|
String json = gson.toJson(INPUT);
|
||||||
|
// Make sure the default uses LF, like before.
|
||||||
|
assertEquals(EXPECTED_LF, json);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNewlineCrLf() {
|
||||||
|
FormattingStyle style = FormattingStyle.DEFAULT.withNewline("\r\n");
|
||||||
|
Gson gson = new GsonBuilder().setPrettyPrinting(style).create();
|
||||||
|
String json = gson.toJson(INPUT);
|
||||||
|
assertEquals(EXPECTED_CRLF, json);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNewlineLf() {
|
||||||
|
FormattingStyle style = FormattingStyle.DEFAULT.withNewline("\n");
|
||||||
|
Gson gson = new GsonBuilder().setPrettyPrinting(style).create();
|
||||||
|
String json = gson.toJson(INPUT);
|
||||||
|
assertEquals(EXPECTED_LF, json);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNewlineCr() {
|
||||||
|
FormattingStyle style = FormattingStyle.DEFAULT.withNewline("\r");
|
||||||
|
Gson gson = new GsonBuilder().setPrettyPrinting(style).create();
|
||||||
|
String json = gson.toJson(INPUT);
|
||||||
|
assertEquals(EXPECTED_CR, json);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNewlineOs() {
|
||||||
|
FormattingStyle style = FormattingStyle.DEFAULT.withNewline(System.lineSeparator());
|
||||||
|
Gson gson = new GsonBuilder().setPrettyPrinting(style).create();
|
||||||
|
String json = gson.toJson(INPUT);
|
||||||
|
assertEquals(EXPECTED_OS, json);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testVariousCombinationsToString() {
|
||||||
|
for (String indent : TEST_INDENTS) {
|
||||||
|
for (String newline : TEST_NEWLINES) {
|
||||||
|
FormattingStyle style = FormattingStyle.DEFAULT.withNewline(newline).withIndent(indent);
|
||||||
|
Gson gson = new GsonBuilder().setPrettyPrinting(style).create();
|
||||||
|
String json = gson.toJson(INPUT);
|
||||||
|
assertEquals(buildExpected(newline, indent), json);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testVariousCombinationsParse() {
|
||||||
|
// Mixing various indent and newline styles in the same string, to be parsed.
|
||||||
|
String jsonStringMix = "[\r\t'v1',\r\n 'v2'\n]";
|
||||||
|
|
||||||
|
String[] actualParsed;
|
||||||
|
// Test all that all combinations of newline can be parsed and generate the same INPUT.
|
||||||
|
for (String indent : TEST_INDENTS) {
|
||||||
|
for (String newline : TEST_NEWLINES) {
|
||||||
|
FormattingStyle style = FormattingStyle.DEFAULT.withNewline(newline).withIndent(indent);
|
||||||
|
Gson gson = new GsonBuilder().setPrettyPrinting(style).create();
|
||||||
|
|
||||||
|
String toParse = buildExpected(newline, indent);
|
||||||
|
actualParsed = gson.fromJson(toParse, INPUT.getClass());
|
||||||
|
assertArrayEquals(INPUT, actualParsed);
|
||||||
|
|
||||||
|
// Parse the mixed string with the gson parsers configured with various newline / indents.
|
||||||
|
actualParsed = gson.fromJson(jsonStringMix, INPUT.getClass());
|
||||||
|
assertArrayEquals(INPUT, actualParsed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStyleValidations() {
|
||||||
|
try {
|
||||||
|
// TBD if we want to accept \u2028 and \u2029. For now we don't.
|
||||||
|
FormattingStyle.DEFAULT.withNewline("\u2028");
|
||||||
|
fail("Gson should not accept anything but \\r and \\n for newline");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
FormattingStyle.DEFAULT.withNewline("NL");
|
||||||
|
fail("Gson should not accept anything but \\r and \\n for newline");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
FormattingStyle.DEFAULT.withIndent("\f");
|
||||||
|
fail("Gson should not accept anything but space and tab for indent");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String buildExpected(String newline, String indent) {
|
||||||
|
return EXPECTED.replace("<EOL>", newline).replace("<INDENT>", indent);
|
||||||
|
}
|
||||||
|
}
|
|
@ -278,8 +278,12 @@ public final class JsonTreeWriterTest {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testOverrides() {
|
public void testOverrides() {
|
||||||
List<String> ignoredMethods = Arrays.asList("setLenient(boolean)", "isLenient()", "setIndent(java.lang.String)",
|
List<String> ignoredMethods = Arrays.asList(
|
||||||
"setHtmlSafe(boolean)", "isHtmlSafe()", "setSerializeNulls(boolean)", "getSerializeNulls()");
|
"setLenient(boolean)", "isLenient()",
|
||||||
|
"setIndent(java.lang.String)",
|
||||||
|
"setHtmlSafe(boolean)", "isHtmlSafe()",
|
||||||
|
"setFormattingStyle(com.google.gson.FormattingStyle)", "getFormattingStyle()",
|
||||||
|
"setSerializeNulls(boolean)", "getSerializeNulls()");
|
||||||
MoreAsserts.assertOverridesMethods(JsonWriter.class, JsonTreeWriter.class, ignoredMethods);
|
MoreAsserts.assertOverridesMethods(JsonWriter.class, JsonTreeWriter.class, ignoredMethods);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ package com.google.gson.stream;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import com.google.gson.FormattingStyle;
|
||||||
import com.google.gson.internal.LazilyParsedNumber;
|
import com.google.gson.internal.LazilyParsedNumber;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
|
@ -844,4 +845,30 @@ public final class JsonWriterTest {
|
||||||
writer.close();
|
writer.close();
|
||||||
writer.close();
|
writer.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetGetFormattingStyle() throws IOException {
|
||||||
|
String lineSeparator = "\r\n";
|
||||||
|
|
||||||
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
JsonWriter jsonWriter = new JsonWriter(stringWriter);
|
||||||
|
jsonWriter.setFormattingStyle(FormattingStyle.DEFAULT.withIndent(" \t ").withNewline(lineSeparator));
|
||||||
|
|
||||||
|
jsonWriter.beginArray();
|
||||||
|
jsonWriter.value(true);
|
||||||
|
jsonWriter.value("text");
|
||||||
|
jsonWriter.value(5.0);
|
||||||
|
jsonWriter.nullValue();
|
||||||
|
jsonWriter.endArray();
|
||||||
|
|
||||||
|
String expected = "[\r\n"
|
||||||
|
+ " \t true,\r\n"
|
||||||
|
+ " \t \"text\",\r\n"
|
||||||
|
+ " \t 5.0,\r\n"
|
||||||
|
+ " \t null\r\n"
|
||||||
|
+ "]";
|
||||||
|
assertThat(stringWriter.toString()).isEqualTo(expected);
|
||||||
|
|
||||||
|
assertThat(jsonWriter.getFormattingStyle().getNewline()).isEqualTo(lineSeparator);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user