Gson でJSON応答を読み取ります。これは、予想されるNumberFormatException
値が空の文字列に設定されているため、int
を時々返します。今、私はこの種の例外を処理する最良の方法は何だろうと思っています。値が空の文字列の場合、逆シリアル化は0になります。
予想されるJSON応答:
{
"name" : "Test1",
"runtime" : 90
}
ただし、ランタイムは空の文字列である場合があります。
{
"name" : "Test2",
"runtime" : ""
}
Javaクラスは次のようになります。
public class Foo
{
private String name;
private int runtime;
}
そして、逆シリアル化はこれです:
String input = "{\n" +
" \"name\" : \"Test\",\n" +
" \"runtime\" : \"\"\n" +
"}";
Gson gson = new Gson();
Foo foo = gson.fromJson(input, Foo.class);
Int値の代わりに空の文字列が返されるため、com.google.gson.JsonSyntaxException: Java.lang.NumberFormatException: empty String
がスローされます。
Gsonに、「Type runtime
のフィールドFoo
をデシリアライズし、NumberFormatExceptionがある場合、デフォルト値0を返すようにする方法はありますか? "?
私の回避策は、String
の代わりにruntime
フィールドのタイプとしてint
を使用することですが、そのようなエラーを処理するより良い方法があるかもしれません。
最初に、NumberFormatException
をキャッチして0を返すために、整数値用の一般的なカスタムタイプアダプターを記述しようとしましたが、Gsonはプリミティブ型のTypeAdaptorsを許可していません。
Java.lang.IllegalArgumentException: Cannot register type adapters for class Java.lang.Integer
その後、FooRuntime
フィールドに新しいType runtime
を導入したので、Foo
クラスは次のようになります。
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;
}
}
タイプアダプタは、カスタムデシリアライゼーションプロセスを処理します。
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());
}
}
型アダプタを登録するにはGsonBuilder
を使用する必要があるため、空の文字列はNumberFormatException
をスローする代わりに0として解釈されます。
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);
これは私がLong型に対して行った例です。これはより良いオプションです:
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);
}
}
詳しくは このリンク を参照してください。
すばやく簡単な回避策-ランタイムのメンバータイプフィールドをStringに変更し、ランタイムをintとして返すゲッターを介してアクセスするだけです。
public class Foo
{
private String name;
private String runtime;
public int getRuntime(){
if(runtime == null || runtime.equals("")){
return 0;
}
return Integer.valueOf(trackId);
}
}
=> JSONのシリアル化解除は不要
空の文字列をチェックして0を返すこのTypeAdapterを作成しました
public class IntegerTypeAdapter extends TypeAdapter<Number> {
@Override
public void write(JsonWriter jsonWriter, Number number) throws IOException {
if (number == null) {
jsonWriter.nullValue();
return;
}
jsonWriter.value(number);
}
@Override
public Number read(JsonReader jsonReader) throws IOException {
if (jsonReader.peek() == JsonToken.NULL) {
jsonReader.nextNull();
return null;
}
try {
String value = jsonReader.nextString();
if ("".equals(value)) {
return 0;
}
return Integer.parseInt(value);
} catch (NumberFormatException e) {
throw new JsonSyntaxException(e);
}
}
}
NumberFormatExceptionの場合、エラーの唯一の原因になる可能性があるため、フィールドruntime
に対して常に0
のデフォルト値を想定すると役立つ場合があります。
Kotlinについてこれに関する回答を探している人は、トップの回答と同じことをしてください。
registerTypeAdapter(Long.class.Java, adapter)
行う
registerTypeAdapter(Java.lang.Long::class.Java, adapter)