- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我正在尝试找到一种使用 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"
}
]
}
}
其中 varKey1
和 varKey2
是未固定/预定义的字符串,因此可以具有任何值。
虽然使用 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 扩展无法为其他复杂情况生成类型适配器的问题。
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;
}
}
与自定义类型的适配器工厂不同,一些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/
我刚刚发现了谷歌的 AutoValue 库,它看起来很棒。我正在尝试编译从 here 下载的示例项目 但是该项目无法编译。编译器提示 AutoValue_ 构造函数符号无法识别。 有人可以解释一下我做
尝试在我的 java 类中使用包 com.google.auto.value.AutoValue 的 AutoValue 并出现错误“AutoValue 无法解析为类型” 我已经在 pom.xml 中
我想在新应用中使用整洁的架构,到目前为止效果很好。我将应用程序结构化为 3 个模块(演示、数据和域),如下例所示:Android-CleanArchitecture 我的域模块中有一些实体。其中之一是
我刚开始使用 AutoValue,但我无法让它与混淆器一起使用。我有大约 6000 多个这样的警告 Warning:autovalue.shaded.com.google.common.auto.co
我正在运行 Eclipse Kepler SR2,Maven 3.1.1 附加了 m2e 和 m2e-apt 插件,我收到一个错误,我不知道如何解决。 我设法找到了获得 @AutoValue 所需的所
我正在使用 AutoValue 扩展来生成我的 Parcelable Android 类。该文档特别指出一个 @AutoValue 不能扩展另一个: https://github.com/google
我有一个 Android 项目,它使用 Autovalue 来生成它的一些模型。我正在尝试从旧的 com.android.support.* 转移到新的 androidx.* 依赖项。 我知道在 An
我有这个 JSON 正文: [ { "id": 0, "field1": "10", "field2": "22" }, {
我正在尝试使用 AutoValueGsonTypeAdapterFactory,但从未生成该类。这是我的实现。 @AutoValue public abstract class Foo { p
我有一个与 RxJava 结合的 Retrofit 接口(interface)。我所有的改造调用都返回 Observable。那些“SomePojo”类,我使用 Schema2Pojo 网站在线生成它
我在 SimpleSchema 中使用以下字段, "fileNo": { type: String, label: "File No.", autoValue: funct
根据AutoValue documentation使用 @GwtCompatible(serializing = true) 注解抽象类并实现可序列化应该足以使生成的值类在 GWT RPC 中可用。然
这可能吗?或者 builder 是唯一的解决方案?拥有一个包含 10 个字段的类意味着必须在构建器中复制这 10 个字段,以便 AutoValue 正常工作。或者通过手动编写的创建函数?或者我错过了什
我试图在我的 Android Studio 项目中使用 Google AutoValue 生成 HomeKey,但它没有忽略 AutoValue_HomeKey() (请参阅下面的注释代码)。使用的g
我正在努力获得 AutoValue在 Android 项目中工作。它似乎对其他人有用,所以我一定只是遗漏了一些东西。我试过启用 jack 编译器,但似乎没有帮助。 Here是一个演示项目,当我在本地构
我有一个带有 List 属性的 Java AutoValue 类。我想允许构建器附加到列表而不是必须传递整个构建的列表。 例子: import com.google.auto.value.AutoVa
我最近在和builder玩auto-value。我处于这种情况,假设我必须将一个现有对象转换为一个新对象,并更新一些属性。示例代码在这里: @AutoValue public abstract cla
我有一个这样的模式(剪掉绒毛): Schemas.people = new SimpleSchema({ note: { type: [Schemas.notes], option
我使用 AutoValue 和 auto-value-with 扩展来创建一个稍微改变的对象。 我的类(class)是: @AutoValue public abstract class FeedIt
假设我有一个简单的 AutoValue 类: @AutoValue abstract class Foo { abstract CommonDependency commonDep(); ab
我是一名优秀的程序员,十分优秀!