Improve documentation (#2193)

* Improve JsonElement subclasses javadoc and add tests

* Slightly improve JsonSerializer and JsonDeserializer javadoc

* Improve ReflectionAccessTest failure message

* Improve documentation regarding field and class exclusion
This commit is contained in:
Marcono1234 2022-09-09 16:32:55 +02:00 committed by GitHub
parent 2266ccdd67
commit 847d7f6638
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 133 additions and 43 deletions

View File

@ -155,7 +155,8 @@ BagOfPrimitives obj2 = gson.fromJson(json, BagOfPrimitives.class);
* While serializing, a null field is omitted from the output.
* While deserializing, a missing entry in JSON results in setting the corresponding field in the object to its default value: null for object types, zero for numeric types, and false for booleans.
* If a field is _synthetic_, it is ignored and not included in JSON serialization or deserialization.
* Fields corresponding to the outer classes in inner classes, anonymous classes, and local classes are ignored and not included in serialization or deserialization.
* Fields corresponding to the outer classes in inner classes are ignored and not included in serialization or deserialization.
* Anonymous and local classes are excluded. They will be serialized as JSON `null` and when deserialized their JSON value is ignored and `null` is returned. Convert the classes to `static` nested classes to enable serialization and deserialization for them.
### <a name="TOC-Nested-Classes-including-Inner-Classes-"></a>Nested Classes (including Inner Classes)

View File

@ -17,11 +17,8 @@
package com.google.gson;
/**
* A strategy (or policy) definition that is used to decide whether or not a field or top-level
* class should be serialized or deserialized as part of the JSON output/input. For serialization,
* if the {@link #shouldSkipClass(Class)} method returns true then that class or field type
* will not be part of the JSON output. For deserialization, if {@link #shouldSkipClass(Class)}
* returns true, then it will not be set as part of the Java object structure.
* A strategy (or policy) definition that is used to decide whether or not a field or
* class should be serialized or deserialized as part of the JSON output/input.
*
* <p>The following are a few examples that shows how you can use this exclusion mechanism.
*
@ -64,7 +61,7 @@ package com.google.gson;
*
* <p>Now if you want to configure {@code Gson} to use a user defined exclusion strategy, then
* the {@code GsonBuilder} is required. The following is an example of how you can use the
* {@code GsonBuilder} to configure Gson to use one of the above sample:
* {@code GsonBuilder} to configure Gson to use one of the above samples:
* <pre class="code">
* ExclusionStrategy excludeStrings = new UserDefinedExclusionStrategy(String.class);
* Gson gson = new GsonBuilder()

View File

@ -156,8 +156,11 @@ public final class GsonBuilder {
/**
* Configures Gson to excludes all class fields that have the specified modifiers. By default,
* Gson will exclude all fields marked transient or static. This method will override that
* behavior.
* Gson will exclude all fields marked {@code transient} or {@code static}. This method will
* override that behavior.
*
* <p>This is a convenience method which behaves as if an {@link ExclusionStrategy} which
* excludes these fields was {@linkplain #setExclusionStrategies(ExclusionStrategy...) registered with this builder}.
*
* @param modifiers the field modifiers. You must use the modifiers specified in the
* {@link java.lang.reflect.Modifier} class. For example,
@ -186,9 +189,12 @@ public final class GsonBuilder {
}
/**
* Configures Gson to exclude all fields from consideration for serialization or deserialization
* Configures Gson to exclude all fields from consideration for serialization and deserialization
* that do not have the {@link com.google.gson.annotations.Expose} annotation.
*
* <p>This is a convenience method which behaves as if an {@link ExclusionStrategy} which excludes
* these fields was {@linkplain #setExclusionStrategies(ExclusionStrategy...) registered with this builder}.
*
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
*/
public GsonBuilder excludeFieldsWithoutExposeAnnotation() {
@ -291,7 +297,20 @@ public final class GsonBuilder {
}
/**
* Configures Gson to exclude inner classes during serialization.
* Configures Gson to exclude inner classes (= non-{@code static} nested classes) during serialization
* and deserialization. This is a convenience method which behaves as if an {@link ExclusionStrategy}
* which excludes inner classes was {@linkplain #setExclusionStrategies(ExclusionStrategy...) registered with this builder}.
* This means inner classes will be serialized as JSON {@code null}, and will be deserialized as
* Java {@code null} with their JSON data being ignored. And fields with an inner class as type will
* be ignored during serialization and deserialization.
*
* <p>By default Gson serializes and deserializes inner classes, but ignores references to the
* enclosing instance. Deserialization might not be possible at all when {@link #disableJdkUnsafe()}
* is used (and no custom {@link InstanceCreator} is registered), or it can lead to unexpected
* {@code NullPointerException}s when the deserialized instance is used afterwards.
*
* <p>In general using inner classes with Gson should be avoided; they should be converted to {@code static}
* nested classes if possible.
*
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
* @since 1.3
@ -369,6 +388,16 @@ public final class GsonBuilder {
* The strategies are added to the existing strategies (if any); the existing strategies
* are not replaced.
*
* <p>Fields are excluded for serialization and deserialization when
* {@link ExclusionStrategy#shouldSkipField(FieldAttributes) shouldSkipField} returns {@code true},
* or when {@link ExclusionStrategy#shouldSkipClass(Class) shouldSkipClass} returns {@code true}
* for the field type. Gson behaves as if the field did not exist; its value is not serialized
* and on deserialization if a JSON member with this name exists it is skipped by default.<br>
* When objects of an excluded type (as determined by
* {@link ExclusionStrategy#shouldSkipClass(Class) shouldSkipClass}) are serialized a
* JSON null is written to output, and when deserialized the JSON value is skipped and
* {@code null} is returned.
*
* @param strategies the set of strategy object to apply during object (de)serialization.
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
* @since 1.4
@ -389,6 +418,9 @@ public final class GsonBuilder {
* class) should be skipped then that field (or object) is skipped during its
* serialization.
*
* <p>See the documentation of {@link #setExclusionStrategies(ExclusionStrategy...)}
* for a detailed description of the effect of exclusion strategies.
*
* @param strategy an exclusion strategy to apply during serialization.
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
* @since 1.7
@ -407,6 +439,9 @@ public final class GsonBuilder {
* class) should be skipped then that field (or object) is skipped during its
* deserialization.
*
* <p>See the documentation of {@link #setExclusionStrategies(ExclusionStrategy...)}
* for a detailed description of the effect of exclusion strategies.
*
* @param strategy an exclusion strategy to apply during deserialization.
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
* @since 1.7

View File

@ -387,11 +387,20 @@ public final class JsonArray extends JsonElement implements Iterable<JsonElement
return getAsSingleElement().getAsBoolean();
}
/**
* Returns whether the other object is equal to this. This method only considers
* the other object to be equal if it is an instance of {@code JsonArray} and has
* equal elements in the same order.
*/
@Override
public boolean equals(Object o) {
return (o == this) || (o instanceof JsonArray && ((JsonArray) o).elements.equals(elements));
}
/**
* Returns the hash code of this array. This method calculates the hash code based
* on the elements of this array.
*/
@Override
public int hashCode() {
return elements.hashCode();

View File

@ -19,7 +19,7 @@ package com.google.gson;
import java.lang.reflect.Type;
/**
* <p>Interface representing a custom deserializer for Json. You should write a custom
* <p>Interface representing a custom deserializer for JSON. You should write a custom
* deserializer, if you are not happy with the default deserialization done by Gson. You will
* also need to register this deserializer through
* {@link GsonBuilder#registerTypeAdapter(Type, Object)}.</p>
@ -42,9 +42,9 @@ import java.lang.reflect.Type;
* </pre>
*
* <p>The default deserialization of {@code Id(com.foo.MyObject.class, 20L)} will require the
* Json string to be <code>{"clazz":com.foo.MyObject,"value":20}</code>. Suppose, you already know
* JSON string to be <code>{"clazz":"com.foo.MyObject","value":20}</code>. Suppose, you already know
* the type of the field that the {@code Id} will be deserialized into, and hence just want to
* deserialize it from a Json string {@code 20}. You can achieve that by writing a custom
* deserialize it from a JSON string {@code 20}. You can achieve that by writing a custom
* deserializer:</p>
*
* <pre>

View File

@ -17,7 +17,7 @@
package com.google.gson;
/**
* A class representing a Json {@code null} value.
* A class representing a JSON {@code null} value.
*
* @author Inderjeet Singh
* @author Joel Leitch
@ -25,16 +25,16 @@ package com.google.gson;
*/
public final class JsonNull extends JsonElement {
/**
* Singleton for JsonNull
* Singleton for {@code JsonNull}.
*
* @since 1.8
*/
public static final JsonNull INSTANCE = new JsonNull();
/**
* Creates a new JsonNull object.
* Creates a new {@code JsonNull} object.
*
* @deprecated Deprecated since Gson version 1.8. Use {@link #INSTANCE} instead
* @deprecated Deprecated since Gson version 1.8, use {@link #INSTANCE} instead.
*/
@Deprecated
public JsonNull() {
@ -42,7 +42,8 @@ public final class JsonNull extends JsonElement {
}
/**
* Returns the same instance since it is an immutable value
* Returns the same instance since it is an immutable value.
*
* @since 2.8.2
*/
@Override
@ -51,7 +52,7 @@ public final class JsonNull extends JsonElement {
}
/**
* All instances of JsonNull have the same hash code since they are indistinguishable
* All instances of {@code JsonNull} have the same hash code since they are indistinguishable.
*/
@Override
public int hashCode() {
@ -59,7 +60,7 @@ public final class JsonNull extends JsonElement {
}
/**
* All instances of JsonNull are the same
* All instances of {@code JsonNull} are considered equal.
*/
@Override
public boolean equals(Object other) {

View File

@ -41,7 +41,8 @@ public final class JsonObject extends JsonElement {
}
/**
* Creates a deep copy of this element and all its children
* Creates a deep copy of this element and all its children.
*
* @since 2.8.2
*/
@Override
@ -55,7 +56,7 @@ public final class JsonObject extends JsonElement {
/**
* Adds a member, which is a name-value pair, to self. The name must be a String, but the value
* can be an arbitrary JsonElement, thereby allowing you to build a full tree of JsonElements
* can be an arbitrary {@link JsonElement}, thereby allowing you to build a full tree of JsonElements
* rooted at this node.
*
* @param property name of the member.
@ -66,10 +67,11 @@ public final class JsonObject extends JsonElement {
}
/**
* Removes the {@code property} from this {@link JsonObject}.
* Removes the {@code property} from this object.
*
* @param property name of the member that should be removed.
* @return the {@link JsonElement} object that is being removed.
* @return the {@link JsonElement} object that is being removed, or {@code null} if no
* member with this name exists.
* @since 1.3
*/
public JsonElement remove(String property) {
@ -77,8 +79,8 @@ public final class JsonObject extends JsonElement {
}
/**
* Convenience method to add a primitive member. The specified value is converted to a
* JsonPrimitive of String.
* Convenience method to add a string member. The specified value is converted to a
* {@link JsonPrimitive} of String.
*
* @param property name of the member.
* @param value the string value associated with the member.
@ -88,8 +90,8 @@ public final class JsonObject extends JsonElement {
}
/**
* Convenience method to add a primitive member. The specified value is converted to a
* JsonPrimitive of Number.
* Convenience method to add a number member. The specified value is converted to a
* {@link JsonPrimitive} of Number.
*
* @param property name of the member.
* @param value the number value associated with the member.
@ -100,10 +102,10 @@ public final class JsonObject extends JsonElement {
/**
* Convenience method to add a boolean member. The specified value is converted to a
* JsonPrimitive of Boolean.
* {@link JsonPrimitive} of Boolean.
*
* @param property name of the member.
* @param value the number value associated with the member.
* @param value the boolean value associated with the member.
*/
public void addProperty(String property, Boolean value) {
add(property, value == null ? JsonNull.INSTANCE : new JsonPrimitive(value));
@ -111,10 +113,10 @@ public final class JsonObject extends JsonElement {
/**
* Convenience method to add a char member. The specified value is converted to a
* JsonPrimitive of Character.
* {@link JsonPrimitive} of Character.
*
* @param property name of the member.
* @param value the number value associated with the member.
* @param value the char value associated with the member.
*/
public void addProperty(String property, Character value) {
add(property, value == null ? JsonNull.INSTANCE : new JsonPrimitive(value));
@ -163,48 +165,63 @@ public final class JsonObject extends JsonElement {
* Returns the member with the specified name.
*
* @param memberName name of the member that is being requested.
* @return the member matching the name. Null if no such member exists.
* @return the member matching the name, or {@code null} if no such member exists.
*/
public JsonElement get(String memberName) {
return members.get(memberName);
}
/**
* Convenience method to get the specified member as a JsonPrimitive element.
* Convenience method to get the specified member as a {@link JsonPrimitive}.
*
* @param memberName name of the member being requested.
* @return the JsonPrimitive corresponding to the specified member.
* @return the {@code JsonPrimitive} corresponding to the specified member, or {@code null} if no
* member with this name exists.
* @throws ClassCastException if the member is not of type {@code JsonPrimitive}.
*/
public JsonPrimitive getAsJsonPrimitive(String memberName) {
return (JsonPrimitive) members.get(memberName);
}
/**
* Convenience method to get the specified member as a JsonArray.
* Convenience method to get the specified member as a {@link JsonArray}.
*
* @param memberName name of the member being requested.
* @return the JsonArray corresponding to the specified member.
* @return the {@code JsonArray} corresponding to the specified member, or {@code null} if no
* member with this name exists.
* @throws ClassCastException if the member is not of type {@code JsonArray}.
*/
public JsonArray getAsJsonArray(String memberName) {
return (JsonArray) members.get(memberName);
}
/**
* Convenience method to get the specified member as a JsonObject.
* Convenience method to get the specified member as a {@link JsonObject}.
*
* @param memberName name of the member being requested.
* @return the JsonObject corresponding to the specified member.
* @return the {@code JsonObject} corresponding to the specified member, or {@code null} if no
* member with this name exists.
* @throws ClassCastException if the member is not of type {@code JsonObject}.
*/
public JsonObject getAsJsonObject(String memberName) {
return (JsonObject) members.get(memberName);
}
/**
* Returns whether the other object is equal to this. This method only considers
* the other object to be equal if it is an instance of {@code JsonObject} and has
* equal members, ignoring order.
*/
@Override
public boolean equals(Object o) {
return (o == this) || (o instanceof JsonObject
&& ((JsonObject) o).members.equals(members));
}
/**
* Returns the hash code of this object. This method calculates the hash code based
* on the members of this object, ignoring order.
*/
@Override
public int hashCode() {
return members.hashCode();

View File

@ -78,6 +78,7 @@ public final class JsonPrimitive extends JsonElement {
/**
* Returns the same value as primitives are immutable.
*
* @since 2.8.2
*/
@Override
@ -243,6 +244,9 @@ public final class JsonPrimitive extends JsonElement {
}
}
/**
* Returns the hash code of this object.
*/
@Override
public int hashCode() {
if (value == null) {
@ -260,6 +264,11 @@ public final class JsonPrimitive extends JsonElement {
return value.hashCode();
}
/**
* Returns whether the other object is equal to this. This method only considers
* the other object to be equal if it is an instance of {@code JsonPrimitive} and
* has an equal value.
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {

View File

@ -19,7 +19,7 @@ package com.google.gson;
import java.lang.reflect.Type;
/**
* Interface representing a custom serializer for Json. You should write a custom serializer, if
* Interface representing a custom serializer for JSON. You should write a custom serializer, if
* you are not happy with the default serialization done by Gson. You will also need to register
* this serializer through {@link com.google.gson.GsonBuilder#registerTypeAdapter(Type, Object)}.
*
@ -43,7 +43,7 @@ import java.lang.reflect.Type;
* </pre>
*
* <p>The default serialization of {@code Id(com.foo.MyObject.class, 20L)} will be
* <code>{"clazz":com.foo.MyObject,"value":20}</code>. Suppose, you just want the output to be
* <code>{"clazz":"com.foo.MyObject","value":20}</code>. Suppose, you just want the output to be
* the value instead, which is {@code 20} in this case. You can achieve that by writing a custom
* serializer:</p>
*

View File

@ -50,6 +50,8 @@ public class JsonObjectTest extends TestCase {
assertEquals(value, removedElement);
assertFalse(jsonObj.has(propertyName));
assertNull(jsonObj.get(propertyName));
assertNull(jsonObj.remove(propertyName));
}
public void testAddingNullPropertyValue() throws Exception {
@ -170,6 +172,22 @@ public class JsonObjectTest extends TestCase {
assertFalse(b.equals(a));
}
public void testEqualsHashCodeIgnoringOrder() {
JsonObject a = new JsonObject();
JsonObject b = new JsonObject();
a.addProperty("1", true);
b.addProperty("2", false);
a.addProperty("2", false);
b.addProperty("1", true);
assertEquals(Arrays.asList("1", "2"), new ArrayList<>(a.keySet()));
assertEquals(Arrays.asList("2", "1"), new ArrayList<>(b.keySet()));
MoreAsserts.assertEqualsAndHashCode(a, b);
}
public void testSize() {
JsonObject o = new JsonObject();
assertEquals(0, o.size());

View File

@ -8,6 +8,7 @@ import static org.junit.Assert.fail;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonIOException;
import com.google.gson.JsonSyntaxException;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
@ -111,8 +112,10 @@ public class ReflectionAccessTest {
// But deserialization should fail
Class<?> internalClass = Collections.emptyList().getClass();
try {
gson.fromJson("{}", internalClass);
gson.fromJson("[]", internalClass);
fail("Missing exception; test has to be run with `--illegal-access=deny`");
} catch (JsonSyntaxException e) {
fail("Unexpected exception; test has to be run with `--illegal-access=deny`");
} catch (JsonIOException expected) {
assertTrue(expected.getMessage().startsWith(
"Failed making constructor 'java.util.Collections$EmptyList#EmptyList()' accessible; "