想象一下以下请求:
@POST("/recipes/create")
void createRecipe(@Query("recipe") Recipe recipe, Callback<String> callback);
我想要json(配方)但不幸的是我的请求只是调用toString()来获取我的配方,这根本不起作用。
我可以覆盖Recipe中的toString但我宁愿有一个通用的解决方案。
我无法使用@Body,因为我需要指定,我要发送的内容(我需要&#34; recipe = json(theRecipe)&#34;。
我也无法更改序列化以添加&#34; recipe =&#34;因为我不负责服务器。
目前我正在使用QueryMap Map放置一个序列化对象。虽然这很有效,但在我看来,它并不是一个很好的解决方案。
我可以以某种方式拦截改装适配器吗?
答案 0 :(得分:8)
现在可以在注册自定义if _, ok := m["Answer"]; ok {
// Do something if set
} else {
// Do something if not set
}
时覆盖Converter.Factory
方法,该方法在解析参数时调用。 @William在2年前提到的Github issue似乎没有更新,因为添加了支持。
方法Javadoc:
返回用于将类型转换为String的Converter,如果此工厂无法处理类型,则返回null。这用于为@Field,@ FieldMap值,@ Header,@ HeaderMap,@ Path,@ Query和@QueryMap值指定的类型创建转换器。
以下示例委托给Gson,但同样可以将任何类型的转换应用于参数。
示例:GsonStringConverterFactory
stringConverter
注册转换器:
要注册自定义转换器,您的“Retrofit”构建器可能如下所示:
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;
}
}
}
}
答案 1 :(得分: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;
}
}
答案 2 :(得分:0)
您可以使用retrofit.RestAdapter.Builder()。setConverter(...)来传递自定义json转换器。
答案 3 :(得分:0)
如@Rolf所述,有一种方法可以设置自定义Converter.Factory
示例:
public class QueryConverterFactory extends Converter.Factory {
public static QueryConverterFactory create() {
return new QueryConverterFactory();
}
private QueryConverterFactory() {
}
@Nullable
@Override
public Converter<?, String> stringConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
if (type == Date.class) {
return DateQueryConverter.INSTANCE;
}
return null;
}
private static final class DateQueryConverter implements Converter<Date, String> {
static final DateQueryConverter INSTANCE = new DateQueryConverter();
private static final ThreadLocal<DateFormat> DF = new ThreadLocal<DateFormat>() {
@Override
public DateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd");
}
};
@Override
public String convert(Date date) {
return DF.get().format(date);
}
}
}
您可以为自己的类型添加转换器。