在Retrofit中序列化查询参数

Fra*_*e91 9 android gson retrofit

想象一下以下要求:

@POST("/recipes/create")
void createRecipe(@Query("recipe") Recipe recipe, Callback<String> callback);
Run Code Online (Sandbox Code Playgroud)

我想要json(食谱),但不幸的是我的请求只是调用toString()为我的食谱,它根本不起作用.

我可以覆盖Recipe中的toString,但我宁愿有一个通用的解决方案.

我不能使用@Body,因为我需要指定,我发送的内容(我需要"recipe = json(theRecipe)").

我也无法更改序列化以添加"recipe =",因为我不负责服务器.

目前我正在使用QueryMap Map,我放入了一个序列化对象.虽然这有效,但在我看来,这不是一个非常好的解决方案.

我可以以某种方式拦截改装适配器吗?

Rol*_* W. 10

现在可以在注册Converter.Factory覆盖stringConverter方法的自定义时执行此操作,该自定义在解析参数时调用.@William在2年前提到的Github问题似乎没有更新,因为增加了支持.

方法Javadoc:

返回用于将类型转换为String的Converter,如果此工厂无法处理类型,则返回null.这用于为@Field,@ FieldMap值,@ Header,@ HeaderMap,@ Path,@ Query和@QueryMap值指定的类型创建转换器.

下面的示例委托给Gson,但同样地,任何类型的转换都可以应用于参数.

示例:GsonStringConverterFactory

class GsonStringConverterFactory
    extends Converter.Factory {

    private final transient Gson gson;

    GsonStringConverterFactory(final Gson gson) {

        this.gson = gson;
    }

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

        final TypeAdapter typeAdapter;
        typeAdapter = gson.getAdapter(TypeToken.get(type));

        return new StringConverter<>(typeAdapter);
    }

    private static class StringConverter<T>
            implements Converter<T, String> {

        private final TypeAdapter<T> typeAdapter;

        private StringConverter(final TypeAdapter<T> typeAdapter) {

            this.typeAdapter = typeAdapter;
        }

        @Override
        public String convert(final T value)
                throws IOException {

            /* This works in our case because parameters in this REST api are always some kind of scalar 
             * and the toJson method converts these to simple json types. */
            final String jsonValue;
            jsonValue = typeAdapter.toJson(value));

            if (jsonValue.startsWith("\"") && jsonValue.endsWith("\"") {
                /* Strip enclosing quotes for json String types */
                return jsonValue.substring(1, jsonValue.length() - 1);
            } else {
                return jsonValue;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

注册转换器:

要注册自定义转换器,您的Retrofit构建器可能如下所示:

    new Retrofit.Builder().baseUrl(BASE_URL)
                          .addConverterFactory(GsonConverterFactory.create(gson))
                          .addConverterFactory(new GsonStringConverterFactory(gson))
                          .build();
Run Code Online (Sandbox Code Playgroud)


Wil*_*iam 6

我不认为它现在以一种很好的方式支持它.请作者之一检查此答案:https://github.com/square/retrofit/issues/291

该答案建议的方法是创建一个覆盖该toString()方法的自定义类型,因为Retrofit内部用于String.valueOf(value)将查询或路径参数转换为字符串.

所以,你可以这样:

class Recipe {
  public int id;
  public String title;

  @Override
  public String toString() {
    // You can use a GSON serialization here if you want
    // This is not a robust implementation
    return Integer.toString(id) + "-" + title;
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 显然从那时起就增加了支持.见[下面的回答](http://stackoverflow.com/a/42459356/741217) (3认同)