当前位置: 首页 > 知识库问答 >
问题:

将JSON对象反序列化为对象数组以进行修改

令狐钧
2023-03-14

我在我的Android应用程序中使用了外部API。问题是在响应中,我不知道如何反序列化返回对象列表。我得到的JSON有这样的格式:

{
    "attribute_1": "value",
    "attribute_2": "value",
    "member_1": {
        "param1": "value1",
        "param2": "value2"
    },
    "member_2": {
        "param1": "value1",
        "param2": "value2"
    },
    ...
}

改装中的API调用如下所示:

@GET("apiednpoint/path")
Call<List<Member>> getMembers();

我想忽略属性,并从该响应中检索list 。我知道我可以创建一个自定义的反序列化器,像这里这样忽略JSON中的一些字段,并像这里这样将成员转换为数组,但是在第二个链接中,我需要一个包装器类来形成我所期望的我的list 。有没有可能在我的列表/数组周围没有包装器?

共有1个答案

暨弘懿
2023-03-14

它不是免费的,但可以通过改进(对于独立的Gson并不容易,因为它需要更多的“魔法”)。下面的解决方案远非完美,但您可以根据需要加以改进。假设您让他跟随member映射:

final class Member {

    final String param1 = null;
    final String param2 = null;

}

和以下服务:

interface IService {

    @GET("/")
    @ByRegExp("member_.+")
    Call<List<Member>> getMembers();

}

请注意,@ByRegexp是一个自定义注释,将在下面进行处理。注释声明:

@Retention(RUNTIME)
@Target(METHOD)
@interface ByRegExp {

    String value();

}
// This is just a mocked HTTP client that always returns your members.json
final OkHttpClient client = new OkHttpClient.Builder()
        .addInterceptor(staticResponse(Q43925012.class, "members.json"))
        .build();
// Gson stuff
final Gson gson = new GsonBuilder()
        // ... configure your Gson here ...
        .create();
final Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("http://whatever")
        .client(client)
        .addConverterFactory(new Converter.Factory() {
            @Override
            public Converter<ResponseBody, ?> responseBodyConverter(final Type type, final Annotation[] annotations, final Retrofit retrofit) {
                // Checking if the method is declared with @ByRegExp annotation
                final ByRegExp byRegExp = findByRegExp(annotations);
                if ( byRegExp != null ) {
                    // If so, then compile the regexp pattern
                    final Pattern pattern = Pattern.compile(byRegExp.value());
                    // And resolve the list element type
                    final Type listElementType = getTypeParameter0(type);
                    // Obtaining the original your-type list type adapter
                    final TypeAdapter<?> listElementTypeAdapter = gson.getAdapter(TypeToken.get(listElementType));
                    return (Converter<ResponseBody, Object>) responseBody -> {
                        try {
                            // Getting input stream from the response body and converting it to a JsonReader -- a low level JSON parser
                            final JsonReader jsonReader = new JsonReader(new InputStreamReader(responseBody.byteStream()));
                            final List<Object> list = new ArrayList<>();
                            // Make sure that the first token is `{`
                            jsonReader.beginObject();
                            // And iterate over each JSON property
                            while ( jsonReader.hasNext() ) {
                                final String name = jsonReader.nextName();
                                final Matcher matcher = pattern.matcher(name);
                                // Check if the property need matches the pattern
                                if ( matcher.matches() ) {
                                    // And if so, just deserialize it and put it to the result list
                                    final Object element = listElementTypeAdapter.read(jsonReader);
                                    list.add(element);
                                } else {
                                    // Or skip the value entirely
                                    jsonReader.skipValue();
                                }
                            }
                            // make sure that the current JSON token is `{` - NOT optional
                            jsonReader.endObject();
                            return list;
                        } finally {
                            responseBody.close();
                        }
                    };
                }
                return super.responseBodyConverter(type, annotations, retrofit);
            }

            private ByRegExp findByRegExp(final Annotation[] annotations) {
                for ( final Annotation annotation : annotations ) {
                    if ( annotation instanceof ByRegExp ) {
                        return (ByRegExp) annotation;
                    }
                }
                return null;
            }

            // Trying to resolve how List<E> is parameterized (or raw if not)
            private Type getTypeParameter0(final Type type) {
                if ( !(type instanceof ParameterizedType) ) {
                    return Object.class;
                }
                final ParameterizedType parameterizedType = (ParameterizedType) type;
                return parameterizedType.getActualTypeArguments()[0];
            }
        })
        .addConverterFactory(GsonConverterFactory.create(gson))
        .build();
final IService service = retrofit.create(IService.class);
final List<Member> members = service.getMembers()
        .execute()
        .body();
for ( final Member member : members ) {
    System.out.println(member.param1 + ", " + member.param2);
}

value1,value2
value1,value2

我不认为它可以更容易实现(在GSON/reverfit交互方面),但我希望它有所帮助。

 类似资料:
  • 问题内容: 我有由第三方编码为固定长度数组的json’ed 元组数组: 我想使用json魔术来获取的实例列表 请帮助我放置适当的注释,以使ObjectMapper发挥作用。 我无法控制传入的格式,而我所有的google’n都以答案来回答如何将适当的json对象(而非数组)数组映射到对象列表 问题答案: 添加以下注释: 并且它应该根据需要序列化条目。 另外:然后使用它来强制执行特定顺序是最安全的,因

  • 问题内容: 我在使用AJAX访问的Java服务器应用程序中有一个字符串。它看起来像以下内容: 当从服务器提取字符串时,是否有一种简单的方法可以将其转换为活动的JavaScript对象(或数组)?还是我必须手动拆分字符串并手动构建对象? 问题答案: 现代浏览器支持。 在不浏览器,您可以包括在库中。

  • 我有一个回应 正文 下面是我要映射的coreV2Response类

  • 问题内容: 在C#中,我已经通过使用如下代码成功将匿名对象序列化为JSON … 但是,我以后想要做的是将JSON字符串反序列化为一个匿名对象。像这样 但是serializer.Deserialize()方法需要第二个参数,该参数是将反序列化到的对象的类型。 我试过了 但这会产生错误: 没有为’<> f__AnonymousType0`2 [[System.Int32,mscorlib,Versio

  • 问题内容: 如何在JavaScript中将对象序列化为JSON? 问题答案: 您正在寻找。

  • 我有以下JSON文件要反序列化