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()
相关推荐
a31582380611 小时前
Android Framework开发知识点整理
android·java·linux·服务器·framework·android源码开发
k***825111 小时前
图文详述:MySQL的下载、安装、配置、使用
android·mysql·adb
小七有话说12 小时前
DevUI与企业级中后台系统融合:低代码表单构建器实战
android·rxjava·devui
暗碳12 小时前
安卓abx二进制xml文件转换普通xml文件
android·xml
4z3313 小时前
Android15 Framework(3):系统服务进程 SystemServer 解析
android·源码阅读
没有了遇见13 小时前
Android 之Google Play bundletool 校验 AAB包
android·google
yuanhello14 小时前
【Android】Android的键值对存储方案对比
android·java·android studio
Ditglu.14 小时前
CentOS7 MySQL5.7 主从复制最终版搭建流程(避坑完整版)
android·adb
恋猫de小郭14 小时前
Android Studio Otter 2 Feature 发布,最值得更新的 Android Studio
android·前端·flutter
走在路上的菜鸟14 小时前
Android学Dart学习笔记第十二节 函数
android·笔记·学习·flutter