Pregunta ¿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?

Ver pregunta similar aquí. ¿O es esta respuesta correcta que debe estar en forma de url codificado y pasado 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 el resentidos de una vez por todas. Una persona respondió que no usa Retrofit. El otro no estaba seguro de la sintaxis. 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?


187
2018-01-28 06:40


origen


Respuestas:


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

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

Dado que Retrofit usa Gson por defecto, el FooRequest las instancias 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 tener 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, por favor, 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 declaración anterior:

  1. Utilizar 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 un TypedJsonString clase:

    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.


361
2018-01-29 05:47



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

interface Foo {
  @POST("/jayson")
  FooResponse postJson(@Body HashMap<String, Object> body);
}

106
2018-02-25 06:04



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

Usando Retrofit2:

Me encontré con este problema anoche 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 requirió enviar un Map<String,Object> que podría contener algunos valores nulos, convertidos en un JSONObject (que no volará con @FieldMap, tampoco lo hacen los caracteres especiales, algunos se convierten), por lo que sigue la sugerencia de @bnorms, y según lo indicado por Cuadrado:

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 usando RequestBody y ResponseBody:

En su uso de interfaz @Body con RequestBody

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

En tu punto de llamada, crea un RequestBody, indicando que es MediaType y que usa JSONObject para convertir su mapa al formato adecuado:

Map<String, Object> 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<ResponseBody> response = serviceCaller.login("loginpostfix", body);

response.enqueue(new Callback<ResponseBody>()
    {
        @Override
        public void onResponse(Call<ResponseBody> call, retrofit2.Response<ResponseBody> rawResponse)
        {
            try
            {
             //get your response....
              Log.d(TAG, "RetroFit2.0 :RetroGetLogin: " + rawResponse.body().string());
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }

        @Override
        public void onFailure(Call<ResponseBody> call, Throwable throwable)
        {
        // other stuff...
        }
    });

Espero que esto ayude a cualquiera!


102
2018-04-24 09:07



En Retrofit2, Cuando desee enviar sus parámetros en bruto, debe usar Escalares.

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<User> getUser(@Body String body);

}

Actividad

   public class SampleActivity extends AppCompatActivity implements Callback<User> {

    @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<User> userCall = apiInterface.getUser(paramObject.toString());
            userCall.enqueue(this);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }


    @Override
    public void onResponse(Call<User> call, Response<User> response) {
    }

    @Override
    public void onFailure(Call<User> call, Throwable t) {
    }
}

45
2018-05-22 01:54



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<JsonObject> 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<JsonObject> callBackRegistraPagador = new Callback<JsonObject>(){
    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.


31
2017-07-27 16:08



Particularmente me gusta la sugerencia de Jake de TypedString subclase encima. 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 ) ;

7
2018-03-11 13:48



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


3
2018-03-05 18:03



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
  -Lengua de llegada : Java   - Tipo de fuente: JSON   -Anotación estilo: Gson   -seleccionar Incluir getters y setters   -también puede seleccionar Permitir propiedades adicionales

http://www.jsonschema2pojo.org/

4) hacer interfaz para la llamada api

    public interface Webservices {

@POST("ApiUrlpath")
    Call<ResponseBean> 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 esto enlazar 

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<ResponseBean> registerCall = ApiHandler.getApiService().ApiName(ApiJsonMap());
            registerCall.enqueue(new retrofit2.Callback<ResponseBean>() {
                @Override
                public void onResponse(Call<ResponseBean> registerCall, retrofit2.Response<ResponseBean> 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<ResponseBean> 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();
    }
}

3
2018-01-17 11:47



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

0
2017-08-02 19:27