You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现Gson逐字段解析日志并定位解析错误字段?

Solution for Gson Field-by-Field Logging and NumberFormatException Troubleshooting

1. How to Log Field Names and Corresponding Values with Gson

You’ve got two reliable approaches here—pick one based on whether you want a generic solution that works for any model class, or a class-specific implementation with more parsing control:

Option 1: Generic Reflection-Based Approach

This method works for any model annotated with @SerializedName, no need to write custom code per class:

// First parse your JSON into the Item object
Gson gson = new Gson();
String jsonResponse = "{ \"ItemCode\":\"A12\", \"ItemSN\":\"123455672\", \"ItemDesc\":\"Google Pixel\" }";
Item item = gson.fromJson(jsonResponse, Item.class);

// Use reflection to iterate over fields with @SerializedName
Field[] fields = Item.class.getDeclaredFields();
for (Field field : fields) {
    SerializedName serializedName = field.getAnnotation(SerializedName.class);
    if (serializedName != null) {
        field.setAccessible(true); // Bypass private field access restrictions
        try {
            Object fieldValue = field.get(item);
            System.out.printf("%s is %s%n", serializedName.value(), fieldValue);
        } catch (IllegalAccessException e) {
            // Log or handle the exception as needed
            e.printStackTrace();
        }
    }
}

This will output exactly what you need:

ItemCode is A12
ItemSN is 123455672
ItemDesc is Google Pixel

Option 2: Custom TypeAdapter for Class-Specific Logging

If you want to log fields as they’re parsed (instead of after full object creation), create a custom TypeAdapter for your Item class:

public class ItemTypeAdapter extends TypeAdapter<Item> {
    private final Gson gson = new Gson();

    @Override
    public void write(JsonWriter out, Item value) throws IOException {
        // Reuse Gson's default serialization logic if needed
        gson.getAdapter(Item.class).write(out, value);
    }

    @Override
    public Item read(JsonReader in) throws IOException {
        Item item = new Item();
        in.beginObject();
        while (in.hasNext()) {
            String fieldName = in.nextName();
            switch (fieldName) {
                case "ItemCode":
                    String itemCode = in.nextString();
                    item.setItemCode(itemCode);
                    System.out.println("ItemCode is " + itemCode);
                    break;
                case "ItemSN":
                    String itemSN = in.nextString();
                    item.setItemSN(itemSN);
                    System.out.println("ItemSN is " + itemSN);
                    break;
                case "ItemDesc":
                    String itemDesc = in.nextString();
                    item.setItemDesc(itemDesc);
                    System.out.println("ItemDesc is " + itemDesc);
                    break;
                default:
                    in.skipValue(); // Skip unknown fields to avoid parsing errors
                    break;
            }
        }
        in.endObject();
        return item;
    }
}

Register this adapter with your GsonBuilder:

Gson gson = new GsonBuilder()
        .registerTypeAdapter(Item.class, new ItemTypeAdapter())
        .create();

2. Troubleshooting NumberFormatException in Retrofit-Gson-RxJava Setup

Pinpointing invalid numeric fields in large, nested responses is tough—but these fixes will make it straightforward:

Option 1: Custom Safe Number TypeAdapterFactory

Create a factory that wraps Gson’s default number parsers and adds detailed context to NumberFormatException messages. This will tell you exactly which field (including nested paths) has invalid data:

public class SafeNumberTypeAdapterFactory implements TypeAdapterFactory {
    @SuppressWarnings("unchecked")
    @Override
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
        Class<T> rawType = (Class<T>) type.getRawType();
        // Only target numeric types (primitives and wrapper classes)
        boolean isNumeric = Number.class.isAssignableFrom(rawType)
                || rawType == int.class || rawType == long.class
                || rawType == float.class || rawType == double.class;

        if (!isNumeric) {
            return null;
        }

        final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
        return new TypeAdapter<T>() {
            @Override
            public void write(JsonWriter out, T value) throws IOException {
                delegate.write(out, value);
            }

            @Override
            public T read(JsonReader in) throws IOException {
                try {
                    return delegate.read(in);
                } catch (NumberFormatException e) {
                    // Get the full path of the problematic field (e.g., "data.orders[3].total")
                    String fieldPath = in.getPath();
                    // Capture the invalid string value causing the error
                    String invalidValue = in.nextString();
                    // Throw a new exception with clear debugging context
                    throw new NumberFormatException(String.format(
                            "Failed to parse numeric field '%s' with invalid value: '%s'",
                            fieldPath, invalidValue
                    ));
                }
            }
        };
    }
}

Register this factory with your GsonBuilder:

Gson gson = new GsonBuilder()
        .registerTypeAdapterFactory(new SafeNumberTypeAdapterFactory())
        .create();

Now when the error occurs, your exception log will include the exact field path and invalid value, making it trivial to locate the issue.

Option 2: Log Full Response Body with Retrofit Interceptor

Add an OkHttp interceptor to log the raw response body. This lets you cross-reference the error message with the actual JSON:

public class ResponseLoggingInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        Response response = chain.proceed(request);

        // Read and log the response body (note: string() can only be called once, so rebuild the response)
        String responseBody = response.body().string();
        Log.d("RetrofitRawResponse", "Response for " + request.url() + ": " + responseBody);

        // Rebuild the response to pass it along to Retrofit
        return response.newBuilder()
                .body(ResponseBody.create(response.body().contentType(), responseBody))
                .build();
    }
}

Add this interceptor to your OkHttpClient:

OkHttpClient okHttpClient = new OkHttpClient.Builder()
        .addInterceptor(new ResponseLoggingInterceptor())
        .build();

Then use this client in your Retrofit setup:

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("your_base_url")
        .client(okHttpClient)
        .addConverterFactory(GsonConverterFactory.create(gson))
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
        .build();

When the NumberFormatException hits, pull the raw JSON from logs and use the field path from the custom exception to find the problematic value instantly.

内容的提问来源于stack exchange,提问作者DCoder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:40:00