How to handle a NumberFormatException with Gson in deserialization a JSON response
Here is an example that I made for Long
type. This is a better option:
public class LongTypeAdapter extends TypeAdapter<Long> {
@Override
public Long read(JsonReader reader) throws IOException {
if (reader.peek() == JsonToken.NULL) {
reader.nextNull();
return null;
}
String stringValue = reader.nextString();
try {
Long value = Long.valueOf(stringValue);
return value;
} catch (NumberFormatException e) {
return null;
}
}
@Override
public void write(JsonWriter writer, Long value) throws IOException {
if (value == null) {
writer.nullValue();
return;
}
writer.value(value);
}
}
Register an adapter using Gson
util:
Gson gson = new GsonBuilder().registerTypeAdapter(Long.class, new LongTypeAdapter()).create();
You can refer to this link for more.
At first, I tried to write a general custom type adaptor for Integer values, to catch the NumberFormatException
and return 0, but Gson doesn't allow TypeAdaptors for primitive Types:
java.lang.IllegalArgumentException: Cannot register type adapters for class java.lang.Integer
After that I introduced a new Type FooRuntime
for the runtime
field, so the Foo
class now looks like this:
public class Foo
{
private String name;
private FooRuntime runtime;
public int getRuntime()
{
return runtime.getValue();
}
}
public class FooRuntime
{
private int value;
public FooRuntime(int runtime)
{
this.value = runtime;
}
public int getValue()
{
return value;
}
}
A type adaptor handles the custom deserialization process:
public class FooRuntimeTypeAdapter implements JsonDeserializer<FooRuntime>, JsonSerializer<FooRuntime>
{
public FooRuntime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
{
int runtime;
try
{
runtime = json.getAsInt();
}
catch (NumberFormatException e)
{
runtime = 0;
}
return new FooRuntime(runtime);
}
public JsonElement serialize(FooRuntime src, Type typeOfSrc, JsonSerializationContext context)
{
return new JsonPrimitive(src.getValue());
}
}
Now it's necessary to use GsonBuilder
to register the type adapter, so an empty string is interpreted as 0 instead of throwing a NumberFormatException
.
String input = "{\n" +
" \"name\" : \"Test\",\n" +
" \"runtime\" : \"\"\n" +
"}";
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(FooRuntime.class, new FooRuntimeTypeAdapter());
Gson gson = builder.create();
Foo foo = gson.fromJson(input, Foo.class);
Quick and easy workaround - Just change your member type field of runtime to String and access it via getter that returns runtime as an int:
public class Foo
{
private String name;
private String runtime;
public int getRuntime(){
if(runtime == null || runtime.equals("")){
return 0;
}
return Integer.valueOf(trackId);
}
}
=> no json deserialization neccessary