Android 网络请求之json转Bean String类型默认值问题

Android Java和Kotlin 相互调用String空指针问题

场景

1:Retrofit 网络请求数据 通过GsonConverterFactory.create()将数据格式化Bean

2:当Bean的数据中存在String类型的时候 且数据未返回这个属性的时候 Gson会默认将这个属性赋值为Null.

3:所以当业务开发的时候取这个属性的时候时不时的都会出现空指针问题,导致项目不健壮.或者是业务实现的时候会出现大量的判空处理增加代码量影响效率

处理 Null 转为 "" 方案

思路: 因为Gson ObjectTypeAdapter 处理了 当String 类型为空的时候将Null赋值给了String 所以我们只需自定义一个String类型的TypeAdapter 拦截String属性处理将null的时候赋值给"" 就可以了

实现: 通过Retrofit自定义添加的GsonConverterFactory 处理内部持有的Gson 处理这个问题就可以了

scss 复制代码
retrofit = Retrofit.Builder()
    .baseUrl(ServerUrlUtils.getApiBaseUrl())
    .client(httpClient)
    .addConverterFactory(CustomGsonConverterFactory.create())
    .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
    .build()

String类型的适配器:

ini 复制代码
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;

import java.io.IOException;

/**
 * @Author: wkq
 * @Time: 2025/3/27 14:41
 * @Desc: 处理Gson 中String 默认值NULL转为""的适配器
 */
public class StringTypeAdapter extends TypeAdapter<String> {
    @Override
    public void write(JsonWriter out, String value) throws IOException {
        try {
            if (value == null) {
                value = "";
            }
            out.value(value.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public String read(JsonReader in) throws IOException {
        String value;
        try {
            if (in.peek() == JsonToken.NULL) {
                in.nextNull();
                value= "";
                return  value;
            }
            if (in.peek() == JsonToken.STRING) {
                String str = in.nextString();
                if (str == null) {
                    value= "";
                } else {
                    value= str;
                }
            } else {
                value =  in.nextString();
            }

        } catch (Exception e) {
            value="";
        }
        return value;
    }
}

1:方案一自定义GsonConverterFactory

1:自定义 CustomGsonConverterFactory

typescript 复制代码
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapter;
import com.google.gson.reflect.TypeToken;

import java.lang.annotation.Annotation;
import java.lang.reflect.Type;

import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Converter;
import retrofit2.Retrofit;

/**
 * 自定义 数据转换工厂
 */

public final class CustomGsonConverterFactory extends Converter.Factory {

  public static CustomGsonConverterFactory create() {
    //处理String类型默认为Null的情况
    Gson gson=  new GsonBuilder()
            .registerTypeAdapter(String.class, new StringTypeAdapter())
            .create();

    return create(gson);
  }

  @SuppressWarnings("ConstantConditions") // Guarding public API nullability.
  public static CustomGsonConverterFactory create(Gson gson) {
    if (gson == null) throw new NullPointerException("gson == null");
    return new CustomGsonConverterFactory(gson);
  }

  private final Gson gson;

  private CustomGsonConverterFactory(Gson gson) {
    this.gson = gson;
  }

  @Override
  public Converter<ResponseBody, ?> responseBodyConverter(
      Type type, Annotation[] annotations, Retrofit retrofit) {
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
    return new GsonResponseBodyConverter<>(gson, adapter);
  }

  @Override
  public Converter<?, RequestBody> requestBodyConverter(
      Type type,
      Annotation[] parameterAnnotations,
      Annotation[] methodAnnotations,
      Retrofit retrofit) {
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
    return new GsonRequestBodyConverter<>(gson, adapter);
  }
}

2 GsonRequestBodyConverter;

java 复制代码
import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonWriter;

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.Charset;

import okhttp3.MediaType;
import okhttp3.RequestBody;
import okio.Buffer;
import retrofit2.Converter;

final class GsonRequestBodyConverter<T> implements Converter<T, RequestBody> {
  private static final MediaType MEDIA_TYPE = MediaType.get("application/json; charset=UTF-8");
  private static final Charset UTF_8 = Charset.forName("UTF-8");

  private final Gson gson;
  private final TypeAdapter<T> adapter;

  GsonRequestBodyConverter(Gson gson, TypeAdapter<T> adapter) {
    this.gson = gson;
    this.adapter = adapter;
  }

  @Override
  public RequestBody convert(T value) throws IOException {
    Buffer buffer = new Buffer();
    Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);
    JsonWriter jsonWriter = gson.newJsonWriter(writer);
    adapter.write(jsonWriter, value);
    jsonWriter.close();
    return RequestBody.create(MEDIA_TYPE, buffer.readByteString());
  }
}

3:GsonResponseBodyConverter

java 复制代码
import com.google.gson.Gson;
import com.google.gson.JsonIOException;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;

import java.io.IOException;

import okhttp3.ResponseBody;
import retrofit2.Converter;

final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
  private final Gson gson;
  private final TypeAdapter<T> adapter;

  GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
    this.gson = gson;
    this.adapter = adapter;
  }

  @Override
  public T convert(ResponseBody value) throws IOException {
    JsonReader jsonReader = gson.newJsonReader(value.charStream());
    try {
      T result = adapter.read(jsonReader);
      if (jsonReader.peek() != JsonToken.END_DOCUMENT) {
        throw new JsonIOException("JSON document was not fully consumed.");
      }
      return result;
    } finally {
      value.close();
    }
  }
}

2:方案二 只更改

GsonConverterFactory 中的Gson 将适配器添加进Gson对象就可以了

css 复制代码
//处理String类型默认为Null的情况
val gson = GsonBuilder()
    .registerTypeAdapter(String::class.java, StringTypeAdapter())
    .create()
retrofit = Retrofit.Builder()
    .baseUrl(ServerUrlUtils.getApiBaseUrl())
    .client(httpClient)
    .addConverterFactory(GsonConverterFactory.create(gson))
    .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
    .build()
相关推荐
峥嵘life7 小时前
Android16 311Y3 EAP-TLS 网络连接失败分析与修复总结
android·开发语言·人工智能·php
Kapaseker8 小时前
破坏性更新 - 解读 Jetpack Compose 1.12
android·kotlin
雨白8 小时前
我的 UML 学习笔记:结合 Android 实例看懂 4 种常用图表
android·架构
怣疯knight8 小时前
快速判断apk有没有支持16kb页面标准
android
风流 少年9 小时前
Spring AI 2.0:Advisor
android·人工智能·spring
YM52e11 小时前
分页查询的基石:ArkTS 为鸿蒙商品列表设计 LIMIT/OFFSET 的表
android·学习·华为·harmonyos
安卓与AI研习社12 小时前
Android ANR 到底怎么定位?从触发原理到日志判断的完整方法
android
阿pin14 小时前
Android随笔-MVI
android·mvi
leobertlan15 小时前
【好玩系列】训练一个神经网络指导小孩玩游戏
android·机器学习·程序员
Android-Flutter15 小时前
android LeakCanary 工作原理 详解
android·kotlin