Форматирование JSON Body для дооснащения из однострочного значения без модели

Есть ли способ превратить одно значение String (обычный текст, а не 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); 

Retrofit имеет абстрактный класс Converter.Factory , который можно использовать для создания пользовательского HTTP-представления. Вы можете создать конвертер для создания 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 в экземпляр RetoFit

 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); 

Тогда лучше использовать Hashmap<String, String> . Вы можете передать Hashmap непосредственно в теле, используя партитуру с помощью Gson. И если вам нужно использовать несколько мест, то вы можете использовать свою собственную карту, расширяющую 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() 

Надеюсь, это поможет 🙂

Это не обязательно создает тело json, но ваш api может работать с закодированными в url вещами

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

Я использую вот так:

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

Он изменит карту на JsonObject

Intereting Posts