2016-07-06 29 views
5

有没有办法将单个字符串值(纯文本,而不是json)变成带有注释的JSON体?我不想创建这样一个简单的模型。格式JSON从单个字符串值改造没有模型的身体

@POST("foo/{fooId}/bars") 
Observable<Void> postBar(@Path("fooId") String styleId, @Body BarModel bar); 

class BarModel { 
    public String bar; 
} 

能不能给我我所期望的:

{ 
    "bar" : "hello world" 
} 

有没有一种简单的方法与注释做呢?事情是这样的:

@POST("foo/{fooId}/bars") 
Observable<Void> postBar(@Path("fooId") String styleId, @Body("bar") String bar); 
+0

参见本[元讨论(http://meta.stackoverflow.com/q/327487/230513)。 – trashgod

回答

7

改造了,你可以用一个Converter.Factory抽象类做自定义的HTTP表示。如果方法具有特定的注释,您可以创建一个Converter来构造一个okhttp.RequestBody

最终的结果将是这样的:

@POST("/") 
Call<Void> postBar(@Body @Root("bar") String foo) 

和改造:postBar("Hello World"){ "bar" : "Hello World" }

让我们开始吧。

步骤1 - 创建根密钥(Root.java)

/** 
* Denotes the root key of a JSON request. 
* <p> 
* Simple Example: 
* <pre><code> 
* &#64;POST("/") 
* Call&lt;ResponseBody&gt; example(
*  &#64;Root("name") String yourName); 
* </code></pre> 
* Calling with {@code foo.example("Bob")} yields a request body of 
* <code>{name=>"Bob"}</code>. 
* @see JSONConverterFactory 
*/ 
@Documented 
@Target(PARAMETER) 
@Retention(RUNTIME) 
public @interface Root { 
    /** 
    * The value of the JSON root. 
    * Results in {"value" : object} 
    */ 
    String value(); 
} 

步骤2的注释 - 定义Converter.Factory检测所述注解(JSONConverterFactory.java)。我使用Gson进行JSON解析,但您可以使用任何您想要的框架。

/** 
* Converts @Root("key") Value to {"key":json value} using the provided Gson converter. 
*/ 
class JSONConverterFactory extends Converter.Factory { 
    private final Gson gson; 
    private static final MediaType CONTENT_TYPE = 
      MediaType.parse("application/json"); 

    JSONConverterFactory(Gson gson) { 
     this.gson = gson; 
    } 

    @Override 
    public Converter<?, RequestBody> requestBodyConverter(
      Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) { 
     for (Annotation annotation : parameterAnnotations) { 
      if (annotation instanceof Root) { 
       Root rootAnnotation = (Root) annotation; 
       return new JSONRootConverter<>(gson, rootAnnotation.value()); 
      } 
     } 
     return null; 
    } 

    private final class JSONRootConverter<T> implements Converter<T, RequestBody> { 
     private Gson gson; 
     private String rootKey; 

     private JSONRootConverter(Gson gson, String rootKey) { 
      this.gson = gson; 
      this.rootKey = rootKey; 
     } 

     @Override 
     public RequestBody convert(T value) throws IOException { 
      JsonElement element = gson.toJsonTree(value); 
      JsonObject object = new JsonObject(); 
      object.add(this.rootKey, element); 
      return RequestBody.create(CONTENT_TYPE, this.gson.toJson(object)); 
     } 
    } 
} 

第3步 - 安装JSONConverterFactory到您的改造实例

Gson gson = new GsonBuilder().create(); // Or your customized version 
Retrofit.Builder builder = ...; 
builder.addConverterFactory(new JSONConverterFactory(gson)) 

第4步 - 利润

@POST("/") 
Call<Void> postBar(@Body @Root("bar") String foo) 

或者为你的情况:

@POST("foo/{fooId}/bars") 
Observable<Void> postBar(@Body @Root("bar") String barValue, @Path("fooId") String styleId); 
+0

“核心”改造是一个http客户端(并且只有那个$),我问过他们关于在核心库中包括更好的JSON支持,他们不感兴趣,改进是明确设计的扩展,所以这是“正确的”方法根据设计师 – Kevin

+0

@Nick,还有什么可以使这个答案更好/任何理由,你不想接受它吗? – Kevin

+0

我希望有一个单线解决方案,我的问题不得不延长这太过分了,但我会接受它,因为它可能会帮助其他人 –

0

它不一定创建一个JSON的身体,但你的API也许能URL编码的东西

@FormUrlEncoded 
@POST("foo/{fooId}/bars") 
Observable<Void> postBar(@Path("fooId") String styleId, @Field("bar") String bar); 
+0

谢谢,没试过。这不是一个我可以控制的API,所以期待一个像我发布的那样的json体。 (这给了我吧= =你好%20world) –

+0

你仍然可以尝试一下,这可以用来代替身体相当频繁。 –

2

然后更好地使用Hashmap<String, String>工作。通过使用Gson进行分析,您可以直接在主体中传递Hashmap。 如果你需要使用多个地方,那么你可以使用自己的地图扩展HashMap,所以你可以在一行中添加你的值。我张贴我的,它可以帮助你 -

public class PostParams extends HashMap<String, String> { 
    public static PostParams init() { 
     return new PostParams(); 
    } 

    public PostParams add(String param, String value) { 
     put(param, value); 
     return this; 
    } 

    public PostParams add(String param, String[] values) { 
     put(param, new Gson().toJson(values)); 
     return this; 
    } 

    public PostParams add(String param, int[] values) { 
     put(param, new Gson().toJson(values)); 
     return this; 
    } 

    public PostParams add(String param, int value) { 
     put(param, value + ""); 
     return this; 
    } 

    public PostParams addPlatform() { 
     put("Platform", Constants.ANDROID); 
     return this; 
    } 

    public PostParams add(String param, double value) { 
     put(param, new Gson().toJson(value)); 
     return this; 
    } 

    @Override 
    public String toString() { 
     return new Gson().toJson(this); 
    } 
} 

用法会像 -

String postData = new PostParams().add("bar", "Hello World").toString() 

希望这将有助于:)

0

我用像这个:

@POST("url") 
Observable<Response<Object>> login(@Body Map<String, Object> body); 

它将改变映射到JSONObject的