gpt4 book ai didi

android - Map> 的 AutoValue Gson 类型适配器

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:44:57 26 4
gpt4 key购买 nike

我正在尝试找到一种使用 AutoValue 的方法将 JSON obj 反序列化为 Java 类(这也是 Parcelable)

JSON 响应通常采用以下形式,

{
"varKey1": {
"occupations": [
{
"value": "val1",
"name": "name1"
},
{
"value": "val2",
"name": "name2"
}
]
},
"varKey2": {
"occupations": [
{
"value": "val1",
"name": "name1"
},
{
"value": "val2",
"name": "name2"
}
]
}
}

其中 varKey1varKey2 是未固定/预定义的字符串,因此可以具有任何值。

虽然使用 AutoValue Gson,但我很难弄清楚它的 typeAdapter 应该是什么样子,我们将不胜感激任何对此的帮助。

最佳答案

据我了解 AutoValue 和 AutoValue:Gson 扩展的工作原理,您无法反序列化 Map<String, List<Obj>>仅使用这些工具从给定的 JSON 生成,因为它们只是简单的源代码生成器。后者甚至声明为每个 AutoValue 注释对象创建一个简单 Gson TypeAdapterFactory

获取给定的 JSON 和 Map<String, List<Obj>>考虑到这一点,您可以:

  • ... 有Map<String, Wrapper>其中包装类包含 List<Obj> (并为每个 @AutoValue 声明一个类型适配器 - 注释)类,因此有一个名为 Wrapper 的哑中间中介对象
  • ...实现一个不能由 AutoValue 生成的自定义类型适配器:Gson 扩展。

第二个选项并不像听起来那么难,并且可以帮助解决 AutoValue 扩展无法为其他复杂情况生成类型适配器的问题。

声明必要的类型标记

final class TypeTokens {

private TypeTokens() {
}

static final TypeToken<Map<String, List<Obj>>> mapStringToObjListTypeToken = new TypeToken<Map<String, List<Obj>>>() {
};

static final TypeToken<List<Obj>> objListTypeTypeToken = new TypeToken<List<Obj>>() {
};

}

实现自定义类型适配器工厂

Gson 类型适配器工厂用于解析(和绑定(bind))特定类型的适配器,并在必要时将适配器绑定(bind)到 Gson 实例以处理任何 Gson 配置。

final class CustomTypeAdapterFactory
implements TypeAdapterFactory {

private static final TypeAdapterFactory customTypeAdapterFactory = new CustomTypeAdapterFactory();

static TypeAdapterFactory getCustomTypeAdapterFactory() {
return customTypeAdapterFactory;
}

@Override
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
if ( typeToken.getType().equals(mapStringToObjListTypeToken.getType()) ) {
@SuppressWarnings({ "unchecked", "rawtypes" })
final TypeAdapter<T> castTypeAdapter = (TypeAdapter) getMapStringToObjectListTypeAdapter(gson);
return castTypeAdapter;
}
return null;
}

}

请注意,工厂的唯一职责是返回一个特殊类型的适配器,它可以跳过 JSON 中的包装器。如果向工厂要求任何其他类型,返回 null是安全的,让 Gson 尝试选择另一种类型的适配器最匹配(内置或您的配置)。

实现类型适配器

这实际上是 Auto Value: Gson Extension 似乎做不到的。由于类型适配器本质上是面向流的,它们可能看起来太低级,但这是 Gson 可以做的最好的事情,因为流是一种非常有效的技术,它也用于 Auto Value: Gson Extension 生成的内容。

final class MapStringToObjectListTypeAdapter
extends TypeAdapter<Map<String, List<Obj>>> {

private final TypeAdapter<List<Obj>> wrapperAdapter;

private MapStringToObjectListTypeAdapter(final TypeAdapter<List<Obj>> wrapperAdapter) {
this.wrapperAdapter = wrapperAdapter;
}

static TypeAdapter<Map<String, List<Obj>>> getMapStringToObjectListTypeAdapter(final Gson gson) {
return new MapStringToObjectListTypeAdapter(gson.getAdapter(objListTypeTypeToken));
}

@Override
@SuppressWarnings("resource")
public void write(final JsonWriter out, final Map<String, List<Obj>> value)
throws IOException {
if ( value == null ) {
// nulls must be written
out.nullValue();
} else {
out.beginObject();
for ( final Entry<String, List<Obj>> e : value.entrySet() ) {
out.name(e.getKey());
out.beginObject();
out.name("occupations");
wrapperAdapter.write(out, e.getValue());
out.endObject();
}
out.endObject();
}
}

@Override
public Map<String, List<Obj>> read(final JsonReader in)
throws IOException {
// if there's JSON null, then just return nothing
if ( in.peek() == NULL ) {
return null;
}
// or read the map
final Map<String, List<Obj>> result = new LinkedHashMap<>();
// expect the { token
in.beginObject();
// and read recursively until } is occurred
while ( in.peek() != END_OBJECT ) {
// this is the top-most level where varKey# occur
final String key = in.nextName();
in.beginObject();
while ( in.peek() != END_OBJECT ) {
final String wrapperName = in.nextName();
switch ( wrapperName ) {
case "occupations":
// if this is the "occupations" property, delegate the parsing to an underlying type adapter
result.put(key, wrapperAdapter.read(in));
break;
default:
// or just skip the value (or throw an exception, up to you)
in.skipValue();
break;
}
}
in.endObject();
}
in.endObject();
return result;
}

}

汽车值(value)产生工厂

与自定义类型的适配器工厂不同,一些Gson类型的适配器工厂已经生成,可以处理abstract。像什么类Obj是(至少在您的源代码中,而不是生成的代码中)。

@GsonTypeAdapterFactory
abstract class GeneratedTypeAdapterFactory
implements TypeAdapterFactory {

public static TypeAdapterFactory getGeneratedTypeAdapterFactory() {
return new AutoValueGson_GeneratedTypeAdapterFactory();
}

}

如何使用

private static void dump(final Map<?, ?> map) {
for ( final Entry<?, ?> e : map.entrySet() ) {
out.print(e.getKey());
out.print(" => ");
out.println(e.getValue());
}
}

...

final Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(getGeneratedTypeAdapterFactory())
.registerTypeAdapterFactory(getCustomTypeAdapterFactory())
.create();
dump(gson.fromJson(json, mapStringToObjListTypeToken.getType()));

给出以下输出:

varKey1 => [Obj{name=name1, value=val1}, Obj{name=name2, value=val2}]
varKey2 => [Obj{name=name1, value=val1}, Obj{name=name2, value=val2}]

如果您仅使用第一个选项的包装器,则输出如下:

varKey1 => Wrapper{occupations=[Obj{name=name1, value=val1}, Obj{name=name2, value=val2}]}
varKey2 => Wrapper{occupations=[Obj{name=name1, value=val1}, Obj{name=name2, value=val2}]}

关于android - Map<String, List<Obj>> 的 AutoValue Gson 类型适配器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41860610/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com