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()
相关推荐
雨白7 小时前
Jetpack系列(二):Lifecycle与LiveData结合,打造响应式UI
android·android jetpack
kk爱闹9 小时前
【挑战14天学完python和pytorch】- day01
android·pytorch·python
每次的天空11 小时前
Android-自定义View的实战学习总结
android·学习·kotlin·音视频
恋猫de小郭11 小时前
Flutter Widget Preview 功能已合并到 master,提前在体验毛坯的预览支持
android·flutter·ios
断剑重铸之日12 小时前
Android自定义相机开发(类似OCR扫描相机)
android
随心最为安12 小时前
Android Library Maven 发布完整流程指南
android
岁月玲珑12 小时前
【使用Android Studio调试手机app时候手机老掉线问题】
android·ide·android studio
还鮟16 小时前
CTF Web的数组巧用
android
小蜜蜂嗡嗡18 小时前
Android Studio flutter项目运行、打包时间太长
android·flutter·android studio
aqi0018 小时前
FFmpeg开发笔记(七十一)使用国产的QPlayer2实现双播放器观看视频
android·ffmpeg·音视频·流媒体