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()
相关推荐
天天爱吃肉821819 分钟前
新能源汽车热管理核心技术解析:冬季续航提升40%的行业方案
android·python·嵌入式硬件·汽车
快乐觉主吖1 小时前
Unity的日志管理类
android·unity·游戏引擎
明月看潮生1 小时前
青少年编程与数学 01-011 系统软件简介 06 Android操作系统
android·青少年编程·操作系统·系统软件·编程与数学
snetlogon201 小时前
JDK17 Http Request 异步处理 源码刨析
android·网络协议·http
消失的旧时光-19432 小时前
Android USB 通信开发
android·java
吃汉堡吃到饱2 小时前
【Android】浅析View.post()
android
咕噜企业签名分发-淼淼2 小时前
开发源码搭建一码双端应用分发平台教程:逐步分析注意事项
android·ios
betazhou3 小时前
mariadb5.5.56在centos7.6环境安装
android·数据库·adb·mariadb·msyql
doublelixin9 小时前
AOSP (Android11) 集成Google GMS三件套
android
xzkyd outpaper12 小时前
onSaveInstanceState() 和 ViewModel 在数据保存能力差异
android·计算机八股