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()
相关推荐
teacher伟大光荣且正确43 分钟前
Qt Creator 配置 Android 编译环境
android·开发语言·qt
飞猿_SIR3 小时前
Android Exoplayer 实现多个音视频文件混合播放以及音轨切换
android·音视频
HumoChen994 小时前
GZip+Base64压缩字符串在ios上解压报错问题解决(安卓、PC模拟器正常)
android·小程序·uniapp·base64·gzip
沙振宇8 小时前
【HarmonyOS】ArkTS开发应用的横竖屏切换
android·华为·harmonyos
橙子199110169 小时前
Kotlin 中的作用域函数
android·开发语言·kotlin
zimoyin9 小时前
Kotlin 懒初始化值
android·开发语言·kotlin
枣伊吕波10 小时前
第六节第二部分:抽象类的应用-模板方法设计模式
android·java·设计模式
萧然CS10 小时前
使用ADB命令操作Android的apk/aab包
android·adb
_extraordinary_14 小时前
MySQL 事务(二)
android·数据库·mysql
鸿蒙布道师18 小时前
鸿蒙NEXT开发动画案例5
android·ios·华为·harmonyos·鸿蒙系统·arkui·huawei