【问题标题】:Retrofit 2 unwrap envelope error改造 2 解包信封错误
【发布时间】:2018-03-31 15:36:39
【问题描述】:


我使用的 API 基本上有 2 个返回值:
单个对象:

{
  "data": {Foo}
}

或对象列表:

{
  "data": [
    {Bar},
    {Bar},
    ...
  ]
}

所以,我创建了 2 个信封类

class Envelope<T> {

    private T data;

    public T getData() {
        return data;
    }
}

class EnvelopeList<T> {

    private List<T> data;

    public List<T> getData() {
        return data;
    }
}

和服务接口

@GET(PATH)
Call<Envelope<Foo>> get();

@GET(PATH_LIST)
Call<EnvelopeList<Bar>> getList();

使用改造 2 配置

Retrofit.Builder builder = new Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create());

一切正常...

如果我像这样从服务中取出信封

@GET(PATH)
Call<Foo> get();

@GET(PATH_LIST)
Call<List<Bar>> getList();

第一个只返回一个仍在工作的对象,但返回一个 List 的那个会给出错误java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $

所以,我尝试创建一个转换器

public class EnvelopeListConverterFactory extends Converter.Factory {

    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(
            final Type type,
            Annotation[] annotations,
            Retrofit retrofit) {

        Type envelopeType = new ParameterizedType() {
            @Override
            public Type[] getActualTypeArguments() {
                return new Type[]{type};
            }

            @Override
            public Type getRawType() {
                return null;
            }

            @Override
            public Type getOwnerType() {
                return EnvelopeList.class;
            }
        };

        Converter<ResponseBody, EnvelopeList> delegate =
                retrofit.nextResponseBodyConverter(this, envelopeType, annotations);

        return new EnvelopeListConverter(delegate);
    }
}

public class EnvelopeListConverter<T> implements Converter<ResponseBody, List<T>> {
    final Converter<ResponseBody, EnvelopeList<T>> delegate;

    EnvelopeListConverter(Converter<ResponseBody, EnvelopeList<T>> delegate) {
        this.delegate = delegate;
    }

    @Override
    public List<T> convert(ResponseBody responseBody) throws IOException {
        EnvelopeList<T> envelope = delegate.convert(responseBody);
        return envelope.getData();
    }
}

如果我创建这样的改造版本

Retrofit.Builder builder = new Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .addConverterFactory(new EnvelopeListConverterFactory());

我仍然得到与以前相同的错误,但如果反转转换器顺序,例如

Retrofit.Builder builder = new Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(new EnvelopeListConverterFactory())
            .addConverterFactory(GsonConverterFactory.create());

错误更改为java.lang.IllegalArgumentException: Unable to create a converter for class Bar for method Service.getList 和返回单个对象的错误,也开始给出相同的错误。

我该怎么做才能让服务返回没有信封的对象?

更新

我想我在我的问题上传递了错误的想法。问题不在于请求可以返回单个对象或列表。我只是试图通过信封并直接获取数据。
我试图这样做http://f2prateek.com/2017/04/21/unwrapping-data-with-retrofit-2/ 但它不起作用

【问题讨论】:

  • 如果{Foo}{Bar} 属于同一类型,您可以将模型中的类型保留为数组或列表,并配置您的对象反序列化器将单个值反序列化为数组。就像杰克逊的情况一样,有JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY。对于 Gson this 可能会有所帮助。
  • 如果我做对了,我现在不知道,但如果我使用它,我的所有响应都将是一个数组(在杰克逊中)?事实并非如此。但我会尝试使用这个 Gson 适配器。谢谢
  • 看看这个,和这个stackoverflow.com/q/41462409/5689605几乎一样
  • @Debanjan 我没有很好地解释我的问题。我添加了有关该主题的更多信息
  • 我有一个类似的问题。你解决了吗。我不想像你一样在改造接口上使用信封类。普通对象有效,列表无法生成。

标签: java android retrofit2


【解决方案1】:

我终于找到了如何创建一个正确的转换器类,而不需要在每个请求上都使用信封/包装器。

https://hackernoon.com/retrofit-converter-for-wrapped-responses-8919298a549c

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-05
    • 2023-03-30
    • 1970-01-01
    相关资源
    最近更新 更多