Skip to content

Commit

Permalink
Merge branch 'main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
Carpe-Wang authored Nov 7, 2023
2 parents 8ac0ffb + d5952fe commit 1a671b2
Show file tree
Hide file tree
Showing 232 changed files with 11,105 additions and 8,933 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ Despite supporting older Java versions, Gson also provides a JPMS module descrip
These are the optional Java Platform Module System (JPMS) JDK modules which Gson depends on.
This only applies when running Java 9 or newer.

- `java.sql` (optional since Gson 2.8.9)
- `java.sql` (optional since Gson 2.8.9)\
When this module is present, Gson provides default adapters for some SQL date and time classes.

- `jdk.unsupported`, respectively class `sun.misc.Unsafe` (optional)
- `jdk.unsupported`, respectively class `sun.misc.Unsafe` (optional)\
When this module is present, Gson can use the `Unsafe` class to create instances of classes without no-args constructor.
However, care should be taken when relying on this. `Unsafe` is not available in all environments and its usage has some pitfalls,
see [`GsonBuilder.disableJdkUnsafe()`](https://javadoc.io/doc/com.google.code.gson/gson/latest/com.google.gson/com/google/gson/GsonBuilder.html#disableJdkUnsafe()).
Expand Down Expand Up @@ -87,7 +87,7 @@ JDK 11 or newer is required for building, JDK 17 is recommended.

### Contributing

See the [contributing guide](https://github.com/google/.github/blob/master/CONTRIBUTING.md).
See the [contributing guide](https://github.com/google/.github/blob/master/CONTRIBUTING.md).\
Please perform a quick search to check if there are already existing issues or pull requests related to your contribution.

Keep in mind that Gson is in maintenance mode. If you want to add a new feature, please first search for existing GitHub issues, or create a new one to discuss the feature and get feedback.
Expand Down
10 changes: 5 additions & 5 deletions Troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@ For example, let's assume you want to deserialize the following JSON data:
}
```

This will fail with an exception similar to this one: `MalformedJsonException: Use JsonReader.setStrictness(Strictness.LENIENT) to accept malformed JSON at line 5 column 4 path $.languages[2]`
The problem here is the trailing comma (`,`) after `"French"`, trailing commas are not allowed by the JSON specification. The location information "line 5 column 4" points to the `]` in the JSON data (with some slight inaccuracies) because Gson expected another value after `,` instead of the closing `]`. The JSONPath `$.languages[2]` in the exception message also points there: `$.` refers to the root object, `languages` refers to its member of that name and `[2]` refers to the (missing) third value in the JSON array value of that member (numbering starts at 0, so it is `[2]` instead of `[3]`).
This will fail with an exception similar to this one: `MalformedJsonException: Use JsonReader.setStrictness(Strictness.LENIENT) to accept malformed JSON at line 5 column 4 path $.languages[2]`
The problem here is the trailing comma (`,`) after `"French"`, trailing commas are not allowed by the JSON specification. The location information "line 5 column 4" points to the `]` in the JSON data (with some slight inaccuracies) because Gson expected another value after `,` instead of the closing `]`. The JSONPath `$.languages[2]` in the exception message also points there: `$.` refers to the root object, `languages` refers to its member of that name and `[2]` refers to the (missing) third value in the JSON array value of that member (numbering starts at 0, so it is `[2]` instead of `[3]`).
The proper solution here is to fix the malformed JSON data.

To spot syntax errors in the JSON data easily you can open it in an editor with support for JSON, for example Visual Studio Code. It will highlight within the JSON data the error location and show why the JSON data is considered invalid.
Expand Down Expand Up @@ -178,8 +178,8 @@ And you want to deserialize the following JSON data:
}
```

This will fail with an exception similar to this one: `IllegalStateException: Expected a string but was BEGIN_ARRAY at line 2 column 17 path $.languages`
This means Gson expected a JSON string value but found the beginning of a JSON array (`[`). The location information "line 2 column 17" points to the `[` in the JSON data (with some slight inaccuracies), so does the JSONPath `$.languages` in the exception message. It refers to the `languages` member of the root object (`$.`).
This will fail with an exception similar to this one: `IllegalStateException: Expected a string but was BEGIN_ARRAY at line 2 column 17 path $.languages`
This means Gson expected a JSON string value but found the beginning of a JSON array (`[`). The location information "line 2 column 17" points to the `[` in the JSON data (with some slight inaccuracies), so does the JSONPath `$.languages` in the exception message. It refers to the `languages` member of the root object (`$.`).
The solution here is to change in the `WebPage` class the field `String languages` to `List<String> languages`.

## <a id="adapter-not-null-safe"></a> `IllegalStateException`: "Expected ... but was NULL"
Expand Down Expand Up @@ -287,7 +287,7 @@ This will not initialize arbitrary classes, and it will throw a `ClassCastExcept

## <a id="type-token-raw"></a> `IllegalStateException`: 'TypeToken must be created with a type argument' <br> `RuntimeException`: 'Missing type parameter'

**Symptom:** An `IllegalStateException` with the message 'TypeToken must be created with a type argument' is thrown.
**Symptom:** An `IllegalStateException` with the message 'TypeToken must be created with a type argument' is thrown.
For older Gson versions a `RuntimeException` with message 'Missing type parameter' is thrown.

**Reason:**
Expand Down
2 changes: 1 addition & 1 deletion UserGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ gson.registerTypeAdapter(MyType.class, new MyDeserializer());
gson.registerTypeAdapter(MyType.class, new MyInstanceCreator());
```

`registerTypeAdapter` call checks
`registerTypeAdapter` call checks
1. if the type adapter implements more than one of these interfaces, in that case it registers the adapter for all of them.
2. if the type adapter is for the Object class or JsonElement or any of its subclasses, in that case it throws IllegalArgumentException because overriding the built-in adapters for these types is not supported.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,28 +15,29 @@
*/
package com.google.gson.extras.examples.rawcollections;

import java.util.ArrayList;
import java.util.Collection;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonParser;
import java.util.ArrayList;
import java.util.Collection;

public class RawCollectionsExample {
static class Event {
private String name;
private String source;

private Event(String name, String source) {
this.name = name;
this.source = source;
}

@Override
public String toString() {
return String.format("(name=%s, source=%s)", name, source);
}
}

@SuppressWarnings({ "unchecked", "rawtypes" })
@SuppressWarnings({"unchecked", "rawtypes"})
public static void main(String[] args) {
Gson gson = new Gson();
Collection collection = new ArrayList();
Expand Down
82 changes: 34 additions & 48 deletions extras/src/main/java/com/google/gson/graph/GraphAdapterBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,26 +38,28 @@
import java.util.Map;
import java.util.Queue;

/**
* Writes a graph of objects as a list of named nodes.
*/
/** Writes a graph of objects as a list of named nodes. */
// TODO: proper documentation
public final class GraphAdapterBuilder {
private final Map<Type, InstanceCreator<?>> instanceCreators;
private final ConstructorConstructor constructorConstructor;

public GraphAdapterBuilder() {
this.instanceCreators = new HashMap<>();
this.constructorConstructor = new ConstructorConstructor(instanceCreators, true, Collections.<ReflectionAccessFilter>emptyList());
this.instanceCreators = new HashMap<>();
this.constructorConstructor =
new ConstructorConstructor(
instanceCreators, true, Collections.<ReflectionAccessFilter>emptyList());
}

public GraphAdapterBuilder addType(Type type) {
final ObjectConstructor<?> objectConstructor = constructorConstructor.get(TypeToken.get(type));
InstanceCreator<Object> instanceCreator = new InstanceCreator<Object>() {
@Override
public Object createInstance(Type type) {
return objectConstructor.construct();
}
};
InstanceCreator<Object> instanceCreator =
new InstanceCreator<Object>() {
@Override
public Object createInstance(Type type) {
return objectConstructor.construct();
}
};
return addType(type, instanceCreator);
}

Expand All @@ -79,6 +81,7 @@ public void registerOn(GsonBuilder gsonBuilder) {

static class Factory implements TypeAdapterFactory, InstanceCreator<Object> {
private final Map<Type, InstanceCreator<?>> instanceCreators;

@SuppressWarnings("ThreadLocalUsage")
private final ThreadLocal<Graph> graphThreadLocal = new ThreadLocal<>();

Expand All @@ -95,7 +98,8 @@ public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
final TypeAdapter<T> typeAdapter = gson.getDelegateAdapter(this, type);
final TypeAdapter<JsonElement> elementAdapter = gson.getAdapter(JsonElement.class);
return new TypeAdapter<T>() {
@Override public void write(JsonWriter out, T value) throws IOException {
@Override
public void write(JsonWriter out, T value) throws IOException {
if (value == null) {
out.nullValue();
return;
Expand Down Expand Up @@ -144,7 +148,8 @@ public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
}
}

@Override public T read(JsonReader in) throws IOException {
@Override
public T read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
Expand Down Expand Up @@ -207,13 +212,12 @@ public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
}

/**
* Hook for the graph adapter to get a reference to a deserialized value
* before that value is fully populated. This is useful to deserialize
* values that directly or indirectly reference themselves: we can hand
* out an instance before read() returns.
* Hook for the graph adapter to get a reference to a deserialized value before that value is
* fully populated. This is useful to deserialize values that directly or indirectly reference
* themselves: we can hand out an instance before read() returns.
*
* <p>Gson should only ever call this method when we're expecting it to;
* that is only when we've called back into Gson to deserialize a tree.
* <p>Gson should only ever call this method when we're expecting it to; that is only when we've
* called back into Gson to deserialize a tree.
*/
@Override
public Object createInstance(Type type) {
Expand All @@ -231,60 +235,42 @@ public Object createInstance(Type type) {

static class Graph {
/**
* The graph elements. On serialization keys are objects (using an identity
* hash map) and on deserialization keys are the string names (using a
* standard hash map).
* The graph elements. On serialization keys are objects (using an identity hash map) and on
* deserialization keys are the string names (using a standard hash map).
*/
private final Map<Object, Element<?>> map;

/**
* The queue of elements to write during serialization. Unused during
* deserialization.
*/
/** The queue of elements to write during serialization. Unused during deserialization. */
private final Queue<Element<?>> queue = new ArrayDeque<>();

/**
* The instance currently being deserialized. Used as a backdoor between
* the graph traversal (which needs to know instances) and instance creators
* which create them.
* The instance currently being deserialized. Used as a backdoor between the graph traversal
* (which needs to know instances) and instance creators which create them.
*/
private Element<Object> nextCreate;

private Graph(Map<Object, Element<?>> map) {
this.map = map;
}

/**
* Returns a unique name for an element to be inserted into the graph.
*/
/** Returns a unique name for an element to be inserted into the graph. */
public String nextName() {
return "0x" + Integer.toHexString(map.size() + 1);
}
}

/**
* An element of the graph during serialization or deserialization.
*/
/** An element of the graph during serialization or deserialization. */
static class Element<T> {
/**
* This element's name in the top level graph object.
*/
/** This element's name in the top level graph object. */
private final String id;

/**
* The value if known. During deserialization this is lazily populated.
*/
/** The value if known. During deserialization this is lazily populated. */
private T value;

/**
* This element's type adapter if known. During deserialization this is
* lazily populated.
*/
/** This element's type adapter if known. During deserialization this is lazily populated. */
private TypeAdapter<T> typeAdapter;

/**
* The element to deserialize. Unused in serialization.
*/
/** The element to deserialize. Unused in serialization. */
private final JsonElement element;

Element(T value, String id, TypeAdapter<T> typeAdapter, JsonElement element) {
Expand Down
14 changes: 7 additions & 7 deletions extras/src/main/java/com/google/gson/interceptors/Intercept.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


/**
* Use this annotation to indicate various interceptors for class instances after
* they have been processed by Gson. For example, you can use it to validate an instance
* after it has been deserialized from Json.
* Here is an example of how this annotation is used:
* Use this annotation to indicate various interceptors for class instances after they have been
* processed by Gson. For example, you can use it to validate an instance after it has been
* deserialized from Json. Here is an example of how this annotation is used:
*
* <p>Here is an example of how this annotation is used:
*
* <pre>
* &#64;Intercept(postDeserialize=UserValidator.class)
* public class User {
Expand Down Expand Up @@ -56,8 +56,8 @@
public @interface Intercept {

/**
* Specify the class that provides the methods that should be invoked after an instance
* has been deserialized.
* Specify the class that provides the methods that should be invoked after an instance has been
* deserialized.
*/
@SuppressWarnings("rawtypes")
public Class<? extends JsonPostDeserializer> postDeserialize();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,10 @@
import com.google.gson.stream.JsonWriter;
import java.io.IOException;

/**
* A type adapter factory that implements {@code @Intercept}.
*/
/** A type adapter factory that implements {@code @Intercept}. */
public final class InterceptorFactory implements TypeAdapterFactory {
@Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
Intercept intercept = type.getRawType().getAnnotation(Intercept.class);
if (intercept == null) {
return null;
Expand All @@ -52,11 +51,13 @@ public InterceptorAdapter(TypeAdapter<T> delegate, Intercept intercept) {
}
}

@Override public void write(JsonWriter out, T value) throws IOException {
@Override
public void write(JsonWriter out, T value) throws IOException {
delegate.write(out, value);
}

@Override public T read(JsonReader in) throws IOException {
@Override
public T read(JsonReader in) throws IOException {
T result = delegate.read(in);
postDeserializer.postDeserialize(result);
return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,14 @@
import com.google.gson.InstanceCreator;

/**
* This interface is implemented by a class that wishes to inspect or modify an object
* after it has been deserialized. You must define a no-args constructor or register an
* {@link InstanceCreator} for such a class.
* This interface is implemented by a class that wishes to inspect or modify an object after it has
* been deserialized. You must define a no-args constructor or register an {@link InstanceCreator}
* for such a class.
*
* @author Inderjeet Singh
*/
public interface JsonPostDeserializer<T> {

/**
* This method is called by Gson after the object has been deserialized from Json.
*/
/** This method is called by Gson after the object has been deserialized from Json. */
public void postDeserialize(T object);
}
Loading

0 comments on commit 1a671b2

Please sign in to comment.