Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NumberFormatException in GSON when converting String to double

I am working with a JSON response that is improperly formatted. All fields are being returned as Strings. Unfortunately, I have no control over the return data.

I am using Gson and attempting to parse a JSON object that includes a field like this:

{
        [...]
    "cost": "9.25"
}

It should obviously be printed as a Number. When I try to parse this as a String, Number or double I get a NumberFormatException:

com.google.gson.JsonSyntaxException: java.lang.NumberFormatException: 
        [...]
    at com.myapp.android.LauncherActivity$1.onSuccess(LauncherActivity.java:69)
        [...]
Caused by: java.lang.NumberFormatException: 
    at org.apache.harmony.luni.util.FloatingPointParser.parseDouble(FloatingPointParser.java:267)
    at java.lang.Double.parseDouble(Double.java:285)
    at com.google.gson.stream.JsonReader.nextInt(JsonReader.java:599)
    at com.google.gson.internal.bind.TypeAdapters$7.read(TypeAdapters.java:228)
    ... 19 more

LauncherActivity Line 69:

Item item = gson.fromJson(response, Item.class);

So I followed this similar question and tried creating a TypeAdapter like so:

public class CostTypeAdapter implements JsonDeserializer<Double>, JsonSerializer<Double> {

    public Double deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        Double cost;
        try {
            cost = json.getAsDouble();
        } catch (NumberFormatException e) {
            cost = 0.00d;
        }
        return cost;
    }

    public JsonElement serialize(Double src, Type typeOfSrc, 
            JsonSerializationContext context) {
        return new JsonPrimitive(src);
    }
}

And registered it when creating the GsonBuilder:

GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(Cost.class, new CostTypeAdapter());
Gson gson = builder.create(); 

And my Cost class:

public class Cost {
    private Double value;

    public Cost(Double value) {
        this.value = value;
    }

    public Double getValue() {
        return value;
    }
}

But I get the same NumberFormatException.

Any ideas on whats happening here? Shouldn't this exception be caught in my CostTypeAdapter.deserialize(), at the very least?

Any help/guidance is greatly appreciated.

like image 514
Paul Burke Avatar asked Feb 11 '12 09:02

Paul Burke


2 Answers

You can also use GsonBuilder's registerTypeAdapter() to catch possible parsing Exceptions and deal with them the way you want.

Example for catching NumberFormatException when parsing Float and make the value null:

    GsonBuilder gb = new GsonBuilder();
    gb.registerTypeAdapter(Float.class, new TypeAdapter<Float>() {

        @Override
        public Float read(JsonReader reader) throws IOException {
            if (reader.peek() == JsonToken.NULL) {
                reader.nextNull();
                return null;
            }
            String stringValue = reader.nextString();
            try {
                Float value = Float.valueOf(stringValue);
                return value;
            } catch (NumberFormatException e) {
                return null;
            }
        }

        @Override
        public void write(JsonWriter writer, Float value) throws IOException {
            if (value == null) {
                writer.nullValue();
                return;
            }
            writer.value(value);
        }

    });
like image 125
pandre Avatar answered Nov 19 '22 04:11

pandre


I ended up having to write a JsonDeserializer for my entire enclosing "Item" class.

public class ItemDeserializer implements JsonDeserializer<Item> {

    @Override
    public Item deserialize(JsonElement json, Type type,
            JsonDeserializationContext context) throws JsonParseException {

        JsonObject jobject = (JsonObject) json;

        return new Item(
                    [...],
                (jobject.has("cost")) ? jobject.get("cost").getAsDouble() : 0.00d
                );
    }
}

Would still love to see a solution for my original issue, so I wouldn't have to manually parse every field.

like image 2
Paul Burke Avatar answered Nov 19 '22 05:11

Paul Burke