notes - use gson library in java




Wie behandelt man eine NumberFormatException mit Gson bei der Deserialisierung einer JSON-Antwort? (5)

Es kann hilfreich sein, im Fall einer NumberFormatException immer einen Standardwert von 0 für die Feldlaufzeit anzunehmen, da dies die einzige Fehlerquelle sein kann.

Ich lese eine JSON-Antwort mit Gson , die manchmal eine NumberFormatException da ein erwarteter int Wert auf eine leere Zeichenfolge gesetzt ist. Jetzt frage ich mich, wie man mit dieser Art von Ausnahme am besten umgehen kann. Wenn der Wert eine leere Zeichenfolge ist, sollte die Deserialisierung 0 sein.

Erwartete JSON-Antwort:

{
   "name" : "Test1",
   "runtime" : 90
}

Aber manchmal ist die Laufzeit eine leere Zeichenfolge:

{
   "name" : "Test2",
   "runtime" : ""
}

Die Java-Klasse sieht folgendermaßen aus:

public class Foo
{
    private String name;
    private int runtime;
}

Und die Deserialisierung ist folgende:

String input = "{\n" +
               "   \"name\" : \"Test\",\n" +
               "   \"runtime\" : \"\"\n" +
               "}";

Gson gson = new Gson();
Foo foo = gson.fromJson(input, Foo.class);

Dabei wird eine com.google.gson.JsonSyntaxException: java.lang.NumberFormatException: empty String da anstelle eines int-Werts ein leerer String zurückgegeben wird.

Gibt es eine Möglichkeit, Gson mitzuteilen, " wenn Sie die Feldlaufzeit des Typs Foo deserialisieren und es eine NumberFormatException gibt, geben Sie einfach den Standardwert 0 zurück "?

Mein Workaround besteht darin, einen String als Typ des runtime anstelle von int . Möglicherweise gibt es jedoch eine bessere Möglichkeit, solche Fehler zu behandeln.


Für alle, die nach einer Antwort für Kotlin suchen, tun Sie dasselbe wie die beste Antwort, anstatt zu tun

registerTypeAdapter(Long.class.java, adapter)

tun

registerTypeAdapter(java.lang.Long::class.java, adapter)


Ich habe diesen TypeAdapter gemacht, der nach leeren Strings sucht und 0 zurückgibt

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);
    }
}

}


Schnelle und einfache Problemumgehung - Ändern Sie einfach Ihr Elementtypfeld der Laufzeit in String und greifen Sie über einen Getter darauf zu, der die Laufzeit als int zurückgibt:

public class Foo
{
    private String name;
    private String runtime;

    public int getRuntime(){
        if(runtime == null || runtime.equals("")){
            return 0;
        }
        return Integer.valueOf(trackId);
    }
}

=> keine json deserialisierung erforderlich


Zuerst habe ich versucht, einen allgemeinen benutzerdefinierten NumberFormatException für Integer-Werte zu schreiben, um die NumberFormatException und 0 zurückzugeben, aber Gson lässt TypeAdaptors für primitive Typen nicht zu:

java.lang.IllegalArgumentException: Cannot register type adapters for class java.lang.Integer

Danach habe ich eine neue Type FooRuntime für das runtime , so dass die Foo Klasse jetzt so aussieht:

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;
    }
}

Ein Typadapter behandelt den benutzerdefinierten Deserialisierungsprozess:

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());
    }
}

Jetzt muss der GsonBuilder mit GsonBuilder registriert werden, sodass eine leere Zeichenfolge als 0 interpretiert wird, anstatt eine 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);






gson