¿CÓMO PUBLICAR JSON entero sin procesar en el cuerpo de una solicitud de reacondicionamiento?

Esta pregunta puede haber sido formulada antes pero no fue definitivamente respondida. ¿Cómo se puede publicar un JSON entero sin procesar dentro del cuerpo de una solicitud de Retrofit?

Vea una pregunta similar aquí . ¿O es correcta esta respuesta que debe ser url codificada y aprobada como un campo ? Realmente espero que no, ya que los servicios a los que me estoy conectando solo están esperando JSON sin procesar en el cuerpo de la publicación. No están configurados para buscar un campo particular para los datos JSON.

Solo quiero aclarar esto con los expertos de una vez por todas. Una persona respondió que no usa Retrofit. El otro no estaba seguro de la syntax. Otro piensa que sí se puede hacer, pero solo si su forma está codificada en url y se coloca en un campo (eso no es aceptable en mi caso). No, no puedo volver a codificar todos los servicios para mi cliente de Android. Y sí, es muy común en los proyectos principales publicar JSON sin formato en lugar de pasar el contenido JSON como valores de propiedades de campo. Vamos a hacerlo bien y seguir. ¿Alguien puede señalar la documentación o el ejemplo que muestra cómo se hace esto? O proporcione una razón válida por la que puede / no debe hacerse.

ACTUALIZACIÓN: Una cosa que puedo decir con 100% de certeza. PUEDE hacer esto en Google Volley. Está integrado. ¿Podemos hacer esto en Retrofit?

La anotación @Body define un único cuerpo de solicitud.

 interface Foo { @POST("/jayson") FooResponse postJson(@Body FooRequest body); } 

Como Retrofit usa Gson de forma predeterminada, las instancias de FooRequest se serializarán como JSON como el único cuerpo de la solicitud.

 public class FooRequest { final String foo; final String bar; FooRequest(String foo, String bar) { this.foo = foo; this.bar = bar; } } 

Llamando con:

 FooResponse = foo.postJson(new FooRequest("kit", "kat")); 

Producirá el siguiente cuerpo:

 {"foo":"kit","bar":"kat"} 

Los documentos de Gson tienen mucho más sobre cómo funciona la serialización de objetos.

Ahora, si realmente desea enviar JSON “en bruto” como el cuerpo usted mismo (pero use Gson para esto), aún puede usar TypedInput :

 interface Foo { @POST("/jayson") FooResponse postRawJson(@Body TypedInput body); } 

TypedInput se define como “Datos binarios con un tipo de mime asociado”. Hay dos formas de enviar datos sin procesar con la statement anterior:

  1. Utilice TypedByteArray para enviar bytes sin procesar y el tipo de mime JSON:

     String json = "{\"foo\":\"kit\",\"bar\":\"kat\"}"; TypedInput in = new TypedByteArray("application/json", json.getBytes("UTF-8")); FooResponse response = foo.postRawJson(in); 
  2. Subclase TypedString para crear una clase TypedJsonString :

     public class TypedJsonString extends TypedString { public TypedJsonString(String body) { super(body); } @Override public String mimeType() { return "application/json"; } } 

    Y luego use una instancia de esa clase similar a la # 1.

En lugar de clases, también podemos usar directamente el HashMap para enviar parámetros del cuerpo, por ejemplo

 interface Foo { @POST("/jayson") FooResponse postJson(@Body HashMap body); } 

Sí, sé que es tarde, pero alguien probablemente se beneficie de esto.

Usando Retrofit2:

JsonObjectRequest me encontré con este problema al migrar de Volley a Retrofit2 (y como dice OP, esto fue incorporado directamente en Volley con JsonObjectRequest ), y aunque la respuesta de Jake es la correcta para Retrofit1.9 , Retrofit2 no tiene TypedString .

Mi caso requería enviar un Map que pudiera contener algunos valores nulos, convertirlo a JSONObject (que no volaría con @FieldMap , ni tampoco caracteres especiales, algunos se convertirían), por lo que se debe seguir @bnorms hint, y como declarado por Square :

Se puede especificar un objeto para su uso como un cuerpo de solicitud HTTP con la anotación @Body.

El objeto también se convertirá usando un convertidor especificado en la instancia de Retrofit. Si no se agrega ningún convertidor, solo se puede usar RequestBody.

Entonces esta es una opción que usa RequestBody y ResponseBody :

En tu interfaz usa @Body con RequestBody

 public interface ServiceApi { @POST("prefix/user/{login}") Call login(@Path("login") String postfix, @Body RequestBody params); } 

En su punto de llamada, cree un RequestBody , estableciendo que es MediaType y usando JSONObject para convertir su Mapa al formato adecuado:

 Map jsonParams = new ArrayMap<>(); //put something inside the map, could be null jsonParams.put("code", some_code); RequestBody body = RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"),(new JSONObject(jsonParams)).toString()); //serviceCaller is the interface initialized with retrofit.create... Call response = serviceCaller.login("loginpostfix", body); response.enqueue(new Callback() { @Override public void onResponse(Call call, retrofit2.Response rawResponse) { try { //get your response.... Log.d(TAG, "RetroFit2.0 :RetroGetLogin: " + rawResponse.body().string()); } catch (Exception e) { e.printStackTrace(); } } @Override public void onFailure(Call call, Throwable throwable) { // other stuff... } }); 

Espero que esto ayude a cualquiera!

En Retrofit2 , cuando quiera enviar sus parámetros en crudo, debe usar Scalars .

primero agrega esto en tu gradle:

 compile 'com.squareup.retrofit2:retrofit:2.3.0' compile 'com.squareup.retrofit2:converter-gson:2.3.0' compile 'com.squareup.retrofit2:converter-scalars:2.3.0' 

Su interfaz

 public interface ApiInterface { String URL_BASE = "http://10.157.102.22/rest/"; @Headers("Content-Type: application/json") @POST("login") Call getUser(@Body String body); } 

Actividad

  public class SampleActivity extends AppCompatActivity implements Callback { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_sample); Retrofit retrofit = new Retrofit.Builder() .baseUrl(ApiInterface.URL_BASE) .addConverterFactory(ScalarsConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .build(); ApiInterface apiInterface = retrofit.create(ApiInterface.class); // prepare call in Retrofit 2.0 try { JSONObject paramObject = new JSONObject(); paramObject.put("email", "sample@gmail.com"); paramObject.put("pass", "4384984938943"); Call userCall = apiInterface.getUser(paramObject.toString()); userCall.enqueue(this); } catch (JSONException e) { e.printStackTrace(); } } @Override public void onResponse(Call call, Response response) { } @Override public void onFailure(Call call, Throwable t) { } } 

Usando JsonObject es la forma en que es:

  1. Crea tu interfaz así:

      public interface laInterfaz{ @POST("/bleh/blah/org") void registerPayer(@Body JsonObject bean, Callback callback); } 
  2. Haga que JsonObject se ajuste a la estructura de jsons.

     JsonObject obj = new JsonObject(); JsonObject payerReg = new JsonObject(); payerReg.addProperty("crc","aas22"); payerReg.addProperty("payerDevManufacturer","Samsung"); obj.add("payerReg",payerReg); /*json/* {"payerReg":{"crc":"aas22","payerDevManufacturer":"Samsung"}} /*json*/ 
  3. Llame al servicio:

      service.registerPayer(obj, callBackRegistraPagador); Callback callBackRegistraPagador = new Callback(){ public void success(JsonObject object, Response response){ System.out.println(object.toString()); } public void failure(RetrofitError retrofitError){ System.out.println(retrofitError.toString()); } 

    };

¡Y eso es! En mi opinión personal, es mucho mejor que hacer pojos y trabajar con el desastre de la clase. Esto es mucho más limpio.

Me gusta especialmente la sugerencia de Jake de la subclase TypedString anterior . De hecho, puede crear una variedad de subclases según el tipo de datos POST que planea subir, cada uno con su propio conjunto personalizado de ajustes consistentes.

También tiene la opción de agregar una anotación de encabezado a sus métodos JSON POST en su API de modificación …

 @Headers( "Content-Type: application/json" ) @POST("/json/foo/bar/") Response fubar( @Body TypedString sJsonBody ) ; 

… pero usar una subclase es, obviamente, autodocumentado.

 @POST("/json/foo/bar") Response fubar( @Body TypedJsonString jsonBody ) ; 

Después de tanto esfuerzo, descubrió que la diferencia básica es que necesita enviar JsonObject lugar de JSONObject como parámetro.

1) Agregar dependencias-

  compile 'com.google.code.gson:gson:2.6.2' compile 'com.squareup.retrofit2:retrofit:2.3.0' compile 'com.squareup.retrofit2:converter-gson:2.3.0' 

2) hacer la clase Api Handler

  public class ApiHandler { public static final String BASE_URL = "URL"; private static Webservices apiService; public static Webservices getApiService() { if (apiService == null) { Gson gson = new GsonBuilder() .setLenient() .create(); Retrofit retrofit = new Retrofit.Builder().addConverterFactory(GsonConverterFactory.create(gson)).baseUrl(BASE_URL).build(); apiService = retrofit.create(Webservices.class); return apiService; } else { return apiService; } } } 

3) hacer clases de frijol de Json schema 2 pojo

Recuerda
– Lenguaje de acceso: Java – Tipo de fuente: JSON – Estilo de anotación: Gson – select Incluye getters y setters – también puedes seleccionar Permitir propiedades adicionales

http://www.jsonschema2pojo.org/

4) hacer interfaz para la llamada api

  public interface Webservices { @POST("ApiUrlpath") Call ApiName(@Body JsonObject jsonBody); } 

si tiene un parámetro de datos de formulario, agregue la línea siguiente

 @Headers("Content-Type: application/x-www-form-urlencoded") 

Otra forma para el parámetro de datos de formulario verifique este enlace

5) hacer JsonObject para pasar al cuerpo como parámetro

  private JsonObject ApiJsonMap() { JsonObject gsonObject = new JsonObject(); try { JSONObject jsonObj_ = new JSONObject(); jsonObj_.put("key", "value"); jsonObj_.put("key", "value"); jsonObj_.put("key", "value"); JsonParser jsonParser = new JsonParser(); gsonObject = (JsonObject) jsonParser.parse(jsonObj_.toString()); //print parameter Log.e("MY gson.JSON: ", "AS PARAMETER " + gsonObject); } catch (JSONException e) { e.printStackTrace(); } return gsonObject; } 

6) Call Api Like this

 private void ApiCallMethod() { try { if (CommonUtils.isConnectingToInternet(MyActivity.this)) { final ProgressDialog dialog; dialog = new ProgressDialog(MyActivity.this); dialog.setMessage("Loading..."); dialog.setCanceledOnTouchOutside(false); dialog.show(); Call registerCall = ApiHandler.getApiService().ApiName(ApiJsonMap()); registerCall.enqueue(new retrofit2.Callback() { @Override public void onResponse(Call registerCall, retrofit2.Response response) { try { //print respone Log.e(" Full json gson => ", new Gson().toJson(response)); JSONObject jsonObj = new JSONObject(new Gson().toJson(response).toString()); Log.e(" responce => ", jsonObj.getJSONObject("body").toString()); if (response.isSuccessful()) { dialog.dismiss(); int success = response.body().getSuccess(); if (success == 1) { } else if (success == 0) { } } else { dialog.dismiss(); } } catch (Exception e) { e.printStackTrace(); try { Log.e("Tag", "error=" + e.toString()); dialog.dismiss(); } catch (Resources.NotFoundException e1) { e1.printStackTrace(); } } } @Override public void onFailure(Call call, Throwable t) { try { Log.e("Tag", "error" + t.toString()); dialog.dismiss(); } catch (Resources.NotFoundException e) { e.printStackTrace(); } } }); } else { Log.e("Tag", "error= Alert no internet"); } } catch (Resources.NotFoundException e) { e.printStackTrace(); } } 

Según la respuesta principal, tengo una solución para no tener que hacer POJO para cada solicitud.

Ejemplo, quiero publicar este JSON.

 { "data" : { "mobile" : "qwer", "password" : "qwer" }, "commom" : {} } 

entonces, creo una clase común como esta:

 import java.util.Map; import java.util.HashMap; public class WRequest { Map data; Map common; public WRequest() { data = new HashMap<>(); common = new HashMap<>(); } } 

Finalmente, cuando necesito un json

 WRequest request = new WRequest(); request.data.put("type", type); request.data.put("page", page); 

La solicitud marcada como @Body puede pasar a Retrofit.

use following para enviar json

 final JSONObject jsonBody = new JSONObject(); try { jsonBody.put("key", "value"); } catch (JSONException e){ e.printStackTrace(); } RequestBody body = RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"),(jsonBody).toString()); 

y pasarlo a url

 @Body RequestBody key