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()