Added a new API method nullSafe() in TypeAdapter that can be used to avoid boilerplate handling of nulls in a type adapter.
This commit is contained in:
parent
538b7ca172
commit
91be944022
@ -16,17 +16,19 @@
|
|||||||
|
|
||||||
package com.google.gson;
|
package com.google.gson;
|
||||||
|
|
||||||
import com.google.gson.internal.bind.JsonElementWriter;
|
|
||||||
import com.google.gson.internal.bind.JsonTreeReader;
|
|
||||||
import com.google.gson.reflect.TypeToken;
|
|
||||||
import com.google.gson.stream.JsonReader;
|
|
||||||
import com.google.gson.stream.JsonWriter;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
|
|
||||||
|
import com.google.gson.internal.bind.JsonElementWriter;
|
||||||
|
import com.google.gson.internal.bind.JsonTreeReader;
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
import com.google.gson.stream.JsonReader;
|
||||||
|
import com.google.gson.stream.JsonToken;
|
||||||
|
import com.google.gson.stream.JsonWriter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts between Java objects and JSON. Applications use type adapters both
|
* Converts between Java objects and JSON. Applications use type adapters both
|
||||||
* for customizing types' JSON forms, and for JSON conversions.
|
* for customizing types' JSON forms, and for JSON conversions.
|
||||||
@ -135,6 +137,63 @@ public abstract class TypeAdapter<T> {
|
|||||||
write(writer, value);
|
write(writer, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This wrapper method is used to make a type adapter null tolerant. In general, a
|
||||||
|
* type adapter is required to handle nulls in write and read methods. Here is how this
|
||||||
|
* is typically done:<br>
|
||||||
|
* <pre>{@code
|
||||||
|
Gson gson = new GsonBuilder().registerTypeAdapter(Foo.class,
|
||||||
|
new TypeAdapter<Foo>() {
|
||||||
|
public Foo read(JsonReader in) throws IOException {
|
||||||
|
if (in.peek() == JsonToken.NULL) {
|
||||||
|
in.nextNull();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// read a Foo from in and return it
|
||||||
|
}
|
||||||
|
public void write(JsonWriter out, Foo src) throws IOException {
|
||||||
|
if (src == null) {
|
||||||
|
out.nullValue();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// write src as JSON to out
|
||||||
|
}
|
||||||
|
).create();
|
||||||
|
* }</pre>
|
||||||
|
* You can avoid this boilerplate handling of nulls by wrapping your type adapter with
|
||||||
|
* {@link #nullSafe(TypeAdapter)} method. Here is how we will rewrite the above example:
|
||||||
|
* <pre>{@code
|
||||||
|
Gson gson = new GsonBuilder().registerTypeAdapter(Foo.class,
|
||||||
|
TypeAdapter.nullSafe(new TypeAdapter<Foo>() {
|
||||||
|
public Foo read(JsonReader in) throws IOException {
|
||||||
|
// read a Foo from in and return it
|
||||||
|
}
|
||||||
|
public void write(JsonWriter out, Foo src) throws IOException {
|
||||||
|
// write src as JSON to out
|
||||||
|
}
|
||||||
|
)).create();
|
||||||
|
* }</pre>
|
||||||
|
* Note that we didn't need to check for nulls in our type adapter after we used nullSafe.
|
||||||
|
*/
|
||||||
|
public static <T> TypeAdapter<T> nullSafe(final TypeAdapter<T> typeAdapter) {
|
||||||
|
return new TypeAdapter<T>() {
|
||||||
|
@Override public void write(JsonWriter out, T value) throws IOException {
|
||||||
|
if (value == null) {
|
||||||
|
out.nullValue();
|
||||||
|
} else {
|
||||||
|
typeAdapter.write(out, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Override public T read(JsonReader reader) throws IOException {
|
||||||
|
if (reader.peek() == JsonToken.NULL) {
|
||||||
|
reader.nextNull();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return typeAdapter.read(reader);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts {@code value} to a JSON document. Unlike Gson's similar {@link
|
* Converts {@code value} to a JSON document. Unlike Gson's similar {@link
|
||||||
* Gson#toJson(Object) toJson} method, this write is strict. Create a {@link
|
* Gson#toJson(Object) toJson} method, this write is strict. Create a {@link
|
||||||
|
@ -16,20 +16,24 @@
|
|||||||
|
|
||||||
package com.google.gson.functional;
|
package com.google.gson.functional;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.google.gson.GsonBuilder;
|
|
||||||
import com.google.gson.TypeAdapter;
|
|
||||||
import com.google.gson.reflect.TypeToken;
|
|
||||||
import com.google.gson.stream.JsonReader;
|
|
||||||
import com.google.gson.stream.JsonWriter;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import com.google.gson.JsonSyntaxException;
|
||||||
|
import com.google.gson.TypeAdapter;
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
import com.google.gson.stream.JsonReader;
|
||||||
|
import com.google.gson.stream.JsonWriter;
|
||||||
|
|
||||||
public final class StreamingTypeAdaptersTest extends TestCase {
|
public final class StreamingTypeAdaptersTest extends TestCase {
|
||||||
private Gson miniGson = new GsonBuilder().create();
|
private Gson miniGson = new GsonBuilder().create();
|
||||||
private TypeAdapter<Truck> truckAdapter = miniGson.getAdapter(Truck.class);
|
private TypeAdapter<Truck> truckAdapter = miniGson.getAdapter(Truck.class);
|
||||||
@ -144,6 +148,39 @@ public final class StreamingTypeAdaptersTest extends TestCase {
|
|||||||
assertTrue(Arrays.toString(array), Arrays.deepEquals(expected, array));
|
assertTrue(Arrays.toString(array), Arrays.deepEquals(expected, array));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testNullSafe() {
|
||||||
|
TypeAdapter<Person> typeAdapter = new TypeAdapter<Person>() {
|
||||||
|
@Override public Person read(JsonReader in) throws IOException {
|
||||||
|
String[] values = in.nextString().split(",");
|
||||||
|
return new Person(values[0], Integer.parseInt(values[1]));
|
||||||
|
}
|
||||||
|
public void write(JsonWriter out, Person person) throws IOException {
|
||||||
|
out.value(person.name + "," + person.age);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Gson gson = new GsonBuilder().registerTypeAdapter(
|
||||||
|
Person.class, typeAdapter).create();
|
||||||
|
Truck truck = new Truck();
|
||||||
|
truck.horsePower = 1.0D;
|
||||||
|
truck.passengers = new ArrayList<Person>();
|
||||||
|
truck.passengers.add(null);
|
||||||
|
try {
|
||||||
|
gson.toJson(truck, Truck.class);
|
||||||
|
fail();
|
||||||
|
} catch (NullPointerException expected) {}
|
||||||
|
String json = "{horsePower:1.0,passengers:[null,null]}";
|
||||||
|
try {
|
||||||
|
gson.fromJson(json, Truck.class);
|
||||||
|
fail();
|
||||||
|
} catch (JsonSyntaxException expected) {}
|
||||||
|
gson = new GsonBuilder().registerTypeAdapter(
|
||||||
|
Person.class, TypeAdapter.nullSafe(typeAdapter)).create();
|
||||||
|
assertEquals("{\"horsePower\":1.0,\"passengers\":[null]}", gson.toJson(truck, Truck.class));
|
||||||
|
truck = gson.fromJson(json, Truck.class);
|
||||||
|
assertEquals(1.0D, truck.horsePower);
|
||||||
|
assertNull(truck.passengers.get(0));
|
||||||
|
}
|
||||||
|
|
||||||
public void testSerializeRecursive() throws IOException {
|
public void testSerializeRecursive() throws IOException {
|
||||||
TypeAdapter<Node> nodeAdapter = miniGson.getAdapter(Node.class);
|
TypeAdapter<Node> nodeAdapter = miniGson.getAdapter(Node.class);
|
||||||
Node root = new Node("root");
|
Node root = new Node("root");
|
||||||
|
Loading…
Reference in New Issue
Block a user