- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
让我们从示例开始:
如果数据正确,应该是( Beijing
cities
为空)
{
"code":200,
"msg":"success",
"data":[
{
"id":1,
"name":"Beijing",
"cities":[]
},
{
"id":2,
"name":"Guangdong",
"cities":[
{
"id":1,
"name":"Guangzhou"
}
]
}
]
}
现在我得到了错误的数据。 ( Beijing
cities
为空)
{
"code":200,
"msg":"success",
"data":[
{
"id":1,
"name":"Beijing",
"cities":null
},
{
"id":2,
"name":"Guangdong",
"cities":[
{
"id":1,
"name":"Guangzhou"
}
]
}
]
}
我正在使用 Retrofit2
ResponseBodyConverter
,实体类:
public class Result<T> {
private int code;
private String msg;
private T data;
// getters, setters
}
public class Province {
private int id;
private String name;
private List<City> cities;
}
public class City {
private int id;
private String name;
}
为了有更好的容错能力,当数据是list的时候,我想自己处理一下。
首先,我尝试使用JsonDeserializer
Gson gson = new GsonBuilder()
.serializeNulls()
.registerTypeHierarchyAdapter(List.class, new GsonListAdapter())
.create();
static class GsonListAdapter implements JsonDeserializer<List<?>> {
@Override
public List<?> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
if (json.isJsonArray()) {
JsonArray array = json.getAsJsonArray();
Type itemType = ((ParameterizedType) typeOfT).getActualTypeArguments()[0];
List list = new ArrayList<>();
for (int i = 0; i < array.size(); i++) {
JsonElement element = array.get(i);
Object item = context.deserialize(element, itemType);
list.add(item);
}
return list;
} else {
return Collections.EMPTY_LIST;
}
}
}
JsonDeserializer
当数据为""
时有效, {}
,和[]
,但是data
是 null
,它不会工作。
然后我尝试使用TypeAdapter
static class GsonListAdapter extends TypeAdapter<List<?>> {
@Override
public void write(JsonWriter out, List<?> value) throws IOException {
out.value(String.valueOf(value));
}
@Override
public List<?> read(JsonReader reader) throws IOException {
if (reader.peek() != JsonToken.BEGIN_ARRAY) {
reader.skipValue();
return Collections.EMPTY_LIST;
}
return new Gson().fromJson(reader, new TypeToken<List<?>>() {}.getType());
}
}
这样一来,无论data
是的,它可以正常工作。我们知道使用TypeToken<List<?>>
会给我们LinkedHashMap
,所以虽然TypeAdapter
可以正常工作,但不知道如何转换JsonReader
到List <?>
.
所以我想知道是否还有其他方法可以处理错误的列表数据?或转换JsonReader
到List <?> data
我想要。
最佳答案
我在Gson
源码中找到了CollectionTypeAdapterFactory
,尝试修改了一下,经过测试,很有用。
public class CollectionTypeAdapterFactory implements TypeAdapterFactory {
private final ConstructorConstructor constructorConstructor;
public CollectionTypeAdapterFactory(ConstructorConstructor constructorConstructor) {
this.constructorConstructor = constructorConstructor;
}
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
Type type = typeToken.getType();
Class<? super T> rawType = typeToken.getRawType();
if (!Collection.class.isAssignableFrom(rawType)) {
return null;
}
Type elementType = $Gson$Types.getCollectionElementType(type, rawType);
TypeAdapter<?> elementTypeAdapter = gson.getAdapter(TypeToken.get(elementType));
ObjectConstructor<T> constructor = constructorConstructor.get(typeToken);
@SuppressWarnings({"unchecked", "rawtypes"}) // create() doesn't define a type parameter
TypeAdapter<T> result = new Adapter(gson, elementType, elementTypeAdapter, constructor);
return result;
}
private static final class Adapter<E> extends TypeAdapter<Collection<E>> {
private final TypeAdapter<E> elementTypeAdapter;
private final ObjectConstructor<? extends Collection<E>> constructor;
public Adapter(Gson context, Type elementType,
TypeAdapter<E> elementTypeAdapter,
ObjectConstructor<? extends Collection<E>> constructor) {
this.elementTypeAdapter =
new TypeAdapterRuntimeTypeWrapper<E>(context, elementTypeAdapter, elementType);
this.constructor = constructor;
}
public Collection<E> read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
//In the source code is return null, I changed to return an empty collection
return constructor.construct();
}
Collection<E> collection = constructor.construct();
in.beginArray();
while (in.hasNext()) {
E instance = elementTypeAdapter.read(in);
collection.add(instance);
}
in.endArray();
return collection;
}
public void write(JsonWriter out, Collection<E> collection) throws IOException {
if (collection == null) {
out.nullValue();
return;
}
out.beginArray();
for (E element : collection) {
elementTypeAdapter.write(out, element);
}
out.endArray();
}
}
}
源代码中的TypeAdapterRuntimeTypeWrapper
是 protected ,我们必须复制一份。
public class TypeAdapterRuntimeTypeWrapper<T> extends TypeAdapter<T> {
private final Gson context;
private final TypeAdapter<T> delegate;
private final Type type;
TypeAdapterRuntimeTypeWrapper(Gson context, TypeAdapter<T> delegate, Type type) {
this.context = context;
this.delegate = delegate;
this.type = type;
}
@Override
public T read(JsonReader in) throws IOException {
return delegate.read(in);
}
@SuppressWarnings({"rawtypes", "unchecked"})
@Override
public void write(JsonWriter out, T value) throws IOException {
TypeAdapter chosen = delegate;
Type runtimeType = getRuntimeTypeIfMoreSpecific(type, value);
if (runtimeType != type) {
TypeAdapter runtimeTypeAdapter = context.getAdapter(TypeToken.get(runtimeType));
if (!(runtimeTypeAdapter instanceof ReflectiveTypeAdapterFactory.Adapter)) {
// The user registered a type adapter for the runtime type, so we will use that
chosen = runtimeTypeAdapter;
} else if (!(delegate instanceof ReflectiveTypeAdapterFactory.Adapter)) {
// The user registered a type adapter for Base class, so we prefer it over the
// reflective type adapter for the runtime type
chosen = delegate;
} else {
// Use the type adapter for runtime type
chosen = runtimeTypeAdapter;
}
}
chosen.write(out, value);
}
private Type getRuntimeTypeIfMoreSpecific(Type type, Object value) {
if (value != null
&& (type == Object.class || type instanceof TypeVariable<?> || type instanceof Class<?>)) {
type = value.getClass();
}
return type;
}
}
使用方法
Gson gson = new GsonBuilder().serializeNulls()
.registerTypeAdapterFactory(
new CollectionTypeAdapterFactory(new ConstructorConstructor(new HashMap<>()))
)
.create();
Result<List<Province>> result = gson.fromJson(jsonStr, new TypeToken<Result<List<Province>>>() {}.getType());
打印:
Result{code=200, msg='success', data=[Province{id=1, name='Beijing', cities=[]}, Province{id=2, name='Guangdong', cities=[City{id=1, name='Guangzhou'}]}]}
关于java - Gson使用TypeAdapter或Json Deserializer将数据从错误列表转换为空列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55085592/
我正在尝试使用 gson 将 json 对象转换为字符串。下面是代码 List studs = //from db int count = studs.size();
我是 json 和 gson 的新手。我有个问题。我有一个父类和一个扩展它的子类。我有一个父类列表。有些是 child 类的。当我使用 gson api toJson() 时,我只获取父类中定义的字段
我遇到了问题,App Engine 将 Long/long 值返回为“String”。这是返回的 JSON 文件的一部分: "stringObject" : "This is a string."
我目前正在实现 Hive在我的 FlutterApp 中。不幸的是,这个错误一直弹出: HiveError: There is already a TypeAdapter for typeId 100
我正在使用 Gson 2.4。 Gson 有一个标志是 null 值应该被序列化还是省略(默认)。当我从省略空值的 Gson 创建一个 TypeAdapter 并通过 TypeAdapter 序列化一
我有一个如下所示的 json 字符串: { "SomeStringProperty": { "value":"StringValue"}, "SomeIntProperty": { "value"
我正在尝试序列化一个类,其中一个成员带有自己的 JSON 序列化实现。我不知道如何将它包含在其余属性中。例如 class Foo { String fieldA; String fie
GSON 似乎在使用某种技巧,它查看我的 JavaBeans 的内部字段,而不是使用可公开访问的属性信息。不幸的是,这对我们来说是行不通的,因为我们神奇地创建的 bean 充满了我不希望它存储的私有(
是否有可能实现以下两个目标? 能够委托(delegate)给调用我们的自定义实现的默认 Gson 反序列化器。 不受 JSON 对象中键的不同顺序的影响 下面我描述了两种可能的方法,但只能实现其中一种
我有一个工作代码,其中我的改造客户端可以从 api 检索对象列表(国家/地区)。问题是,如果我曾经检索所有国家,那么 api 使用的参数返回一个 ARRAY,然后当我想查询一个国家时它返回一个 OBJ
我为包含枚举属性的类编写了一个TypeAdapter。这是 write 方法,它对枚举值使用标准 GSON 序列化: @Override public void write(JsonW
我正在尝试用 Kotlin 语言为我的 android 项目实现一些特定的 GSON TypeAdapter。 我面临的问题是无法推断类型的编译错误:Type inference failed: 'T
我想像这样通过 TypeAdapter 模拟一个传递给 Gson 的对象: @RunWith(MockitoJUnitRunner.class) public class SceneExporterT
因此,我正在尝试使用 Gson 和 Retrofit 解决我的自定义 TypeAdapter 遇到的问题。我一直收到 Expected BEGIN_OBJECT but was STRING 错误,但
让我们从分享工作和可复制代码开始(需要谷歌gson包): package mypackage; import com.google.gson.Gson; import com.google.gson.
我很难找到与此特定场景相关的任何内容 我配置了 Spring Boot,并且在其中使用响应式(Reactive) WebClient 来使用 REST Api。我已将其配置为使用 gson,但想知道如
我正在尝试为我正在使用的 JavaFX 类型(不同的属性和可观察值)编写一个 TypeAdapterFactory。对于 ObjectProperty,我可以编写一个 JsonSerializer/D
我见过很多使用自定义 TypeAdapter 的简单示例。最有帮助的是 Class TypeAdapter .但这还没有回答我的问题。 我想自定义对象中单个字段的序列化,并让默认的 Gson 机制处理
我有一个名为游戏的类: public class Game { private String name; private int id; private GameFields[
我正在 Flutter 中学习 Hive db。当我使用 Flutter 包时 pub run build_runner build命令它在其中生成 data.g.dart 文件它有一个错误。 完整的
我是一名优秀的程序员,十分优秀!