将 String 转换为 double 时 GSON 中的 NumberFormatException

发布于 2025-01-05 03:01:38 字数 2412 浏览 0 评论 0原文

我正在处理格式不正确的 JSON 响应。所有字段都以字符串形式返回。不幸的是,我无法控制返回数据

我正在使用 Gson 并尝试解析包含如下字段的 JSON 对象:

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

它显然应该打印为 Number。当我尝试将其解析为 StringNumberdouble 时,我收到 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);

所以我按照 这个类似的问题并尝试创建一个TypeAdapter 像这样:

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

并在创建 GsonBuilder 时注册它:

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

和我的 Cost 类:

public class Cost {
    private Double value;

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

    public Double getValue() {
        return value;
    }
}

但我得到相同的 NumberFormatException >。

对这里发生的事情有什么想法吗?至少不应该在我的 CostTypeAdapter.deserialize() 中捕获此异常吗?

非常感谢任何帮助/指导。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

荒路情人 2025-01-12 03:01:38

您还可以使用 GsonBuilder 的 registerTypeAdapter() 来捕获可能的解析异常并按照您想要的方式处理它们。

解析 Float 时捕获 NumberFormatException 并将值设为 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);
        }

    });

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

    });
多情癖 2025-01-12 03:01:38

我最终不得不为整个封闭的“Item”类编写一个 JsonDeserializer 。

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

仍然希望看到我原来问题的解决方案,这样我就不必手动解析每个字段。

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.

小鸟爱天空丶 2025-01-12 03:01:38

看起来 Item 类中的 cost 字段被声明为 int,而不是 double。将 cost 更改为 double 应该可以解决这个问题。

It looks like the cost field in your Item class is declared as an int, not as a double. Changing cost to a double should fix it.

來不及說愛妳 2025-01-12 03:01:38

Paul,我在获取 JSON 中存储为 String 的数字时遇到了类似的问题。对我来说一直有效的是:

public enum Plan {
        GUEST_PASS, FREE, PREMIUM;

        static Plan fromValue(int value) {
            for (Plan plan : plans)
                if (value == plan.ordinal())
                    return plan;
            throw new IllegalArgumentException("Invalid value for Plan: " + value);
        }

        static Plan fromValue(String string) {
            try {
                return fromValue(parseInt(string));
            } catch (IllegalArgumentException _) {
                throw new IllegalArgumentException("Invalid value for Plan: " + string);
            }
        }

        private static EnumSet<Plan> plans = EnumSet.allOf(Plan.class);
    }

public static class PlanAdapter extends TypeAdapter<Plan> {
    @Override public void write(JsonWriter json, Plan plan) throws IOException {
        json.value(Integer.toString(plan.ordinal()));
    }

    @Override public Plan read(JsonReader json) throws IOException {
        return Plan.fromValue(json.nextString());
    }
}

在你的情况下似乎有连续的数据,所以你有一个就足够了,因为我有离散数据,所以我转换为枚举。

Paul, I have a similar issue of getting numbers in my JSON that are stored as Strings. What's been working for me is this:

public enum Plan {
        GUEST_PASS, FREE, PREMIUM;

        static Plan fromValue(int value) {
            for (Plan plan : plans)
                if (value == plan.ordinal())
                    return plan;
            throw new IllegalArgumentException("Invalid value for Plan: " + value);
        }

        static Plan fromValue(String string) {
            try {
                return fromValue(parseInt(string));
            } catch (IllegalArgumentException _) {
                throw new IllegalArgumentException("Invalid value for Plan: " + string);
            }
        }

        private static EnumSet<Plan> plans = EnumSet.allOf(Plan.class);
    }

public static class PlanAdapter extends TypeAdapter<Plan> {
    @Override public void write(JsonWriter json, Plan plan) throws IOException {
        json.value(Integer.toString(plan.ordinal()));
    }

    @Override public Plan read(JsonReader json) throws IOException {
        return Plan.fromValue(json.nextString());
    }
}

Seems like you have continuous data in your case, so you would suffice to have a class, I converted to an enum since I had discrete data.

杀手六號 2025-01-12 03:01:38

我也遇到了类似的情况。我使用下面的适配器进行转换。我发现它很简洁。

.registerTypeAdapter(Double.class, new JsonSerializer<Double>() {
            public JsonElement serialize(Double number, Type type, JsonSerializationContext context) {
                return new JsonPrimitive(Double.valueOf(number));
            }
        })

I also ran into a similar situation. I used below adaptor for the conversion. I Found it concise.

.registerTypeAdapter(Double.class, new JsonSerializer<Double>() {
            public JsonElement serialize(Double number, Type type, JsonSerializationContext context) {
                return new JsonPrimitive(Double.valueOf(number));
            }
        })
将军与妓 2025-01-12 03:01:38

最简单的解决方案是将属性设置为 String 而不是 double ,并在 get 方法中将其解析为 double 。

例如:

class Location {
 private String latitude;
 private String longitude;

 public double getLatitude() {
        return latitude.isEmpty() ? 0d : Double.parseDouble(latitude);
    }

    public double getLongitude() {
        return longitude.isEmpty() ? 0d : Double.parseDouble(longitude);
    }
}

the easiest solution is to make the attribute to be String instead of double and in the get method parse it to double.

for example:

class Location {
 private String latitude;
 private String longitude;

 public double getLatitude() {
        return latitude.isEmpty() ? 0d : Double.parseDouble(latitude);
    }

    public double getLongitude() {
        return longitude.isEmpty() ? 0d : Double.parseDouble(longitude);
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文