¿Cómo publicar JSON entero sin procesar en el cuerpo de una solicitud de modificación?

285

Puede que esta pregunta se haya hecho antes, pero no, no se respondió definitivamente. ¿Cómo se publica exactamente un JSON completo sin procesar dentro del cuerpo de una solicitud de modificación?

Ver pregunta similar aquí . ¿O es correcta esta respuesta de que debe estar codificada en URL y pasar como un campo ? Realmente espero que no, ya que los servicios a los que me estoy conectando solo esperan 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 debía usar 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 Android. Y sí, es muy común en proyectos importantes publicar JSON sin formato en lugar de pasar contenido JSON como valores de propiedad de campo. Hagámoslo bien y sigamos adelante. ¿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. PUEDES hacer esto en Google Volley. Está integrado directamente. ¿Podemos hacer esto en Retrofit?

usuario3243335
fuente
77
¡La publicación de Jake Wharton es correcta! Marcar como respuesta!
edotassi
1
Puede usar jsonObject mejor.
superUser
funciona perfectamente RequestBodyasí -> RequestBody body = RequestBody.create(MediaType.parse("text/plain"), text);para respuestas detalladas futurestud.io/tutorials/…
Kidus Tekeste

Respuestas:

460

La @Bodyanotación define un solo cuerpo de solicitud.

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

Dado que Retrofit usa Gson de forma predeterminada, las FooRequestinstancias 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!) Todavía puede usar TypedInput:

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

TypedInput se define como "Datos binarios con un tipo mime asociado". Hay dos formas de enviar fácilmente datos sin procesar con la declaración anterior:

  1. Utilice TypedByteArray para enviar bytes sin formato y el tipo 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 TypedJsonStringclase:

    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 al # 1.

Jake Wharton
fuente
55
Muy bien, sin embargo, ¿hay alguna forma de hacer esto sin hacer los pojos?
superUser
28
Esto no funciona en la actualización 2. Se eliminaron las clases TypedInput y TypedString.
Ahmed Hegazy
2
@jakewharton ¿Qué podemos hacer TypedStringdesde que se eliminó?
Jared Burrows
12
Para Retrofit2, puede usar RequestBodypara crear un cuerpo sin formato.
bnorm
44
Recibo esta excepciónjava.lang.IllegalArgumentException: Unable to create @Body converter for class MatchAPIRequestBody (parameter #1)
Shajeel Afzal
156

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

interface Foo {
  @POST("/jayson")
  FooResponse postJson(@Body HashMap<String, Object> body);
}
aprendiz
fuente
2
En ese momento puede crear un mapa Hash como HashMap <String, Object>, puede ser posible crear matrices y objetos un poco complejos JSON.
alumno
2
Esto es excelente si no desea estar atado a un POJO de algún tipo.
Tim
2
@Nil no puedes enviar objetos json usando retrofit ... te adhieres a pojo o mi respuesta ... esta es la naturaleza de retrofit. .
aprendiz
55
Me pongo IllegalArgumentException: Unable to create @Body converter for java.util.HashMap<java.lang.String, java.lang.Object>con Moshi. Creo que se necesita Gson para que esto funcione
osrl
2
Si usa Kotlin, use un hashmap de <String, Any>
peresisUser
149

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

Usando Retrofit2:

Anoche me encontré con este problema al migrar de Volley a Retrofit2 (y como OP dice, esto se incorporó directamente a 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<String,Object>que pudiera contener algunos valores nulos, convertido a un JSONObject (que no volará con @FieldMap, tampoco caracteres especiales, algunos se convierten), así que siguiendo la sugerencia de @bnorms, y como lo indica Square :

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

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

Entonces esta es una opción usando RequestBodyy ResponseBody:

En su interfaz use @BodyconRequestBody

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

En su punto de llamada, cree un RequestBody, indicando que es MediaType, y usando 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!


Una elegante versión de Kotlin de lo anterior, para permitir abstraer los parámetros de la conversión JSON en el resto del código de su aplicación:

interface ServiceApi {

    fun login(username: String, password: String) =
            jsonLogin(createJsonRequestBody(
                "username" to username, "password" to password))

    @POST("/api/login")
    fun jsonLogin(@Body params: RequestBody): Deferred<LoginResult>

    private fun createJsonRequestBody(vararg params: Pair<String, String>) =
            RequestBody.create(
                okhttp3.MediaType.parse("application/json; charset=utf-8"), 
                JSONObject(mapOf(*params)).toString())

}
TommySM
fuente
2
Sí, estoy viendo muchas respuestas complicadas por todo esto. Si está utilizando Retrofit2 y quiere hacer voleibol JsonObjectRequest, todo lo que necesita hacer es esto. Buena respuesta.
VicVu
2
Retrofit agrega una clave llamada "nameValuePairs" en la parte superior de todos los objetos json. ¿Cómo puedo eliminar esto @TommySM
Nr5
1
¡Gracias! Esto resolvió mi problema. Ahora puedo enviar JSONObject directamente sin crear POJO.
Erfan GLMPR
1
Esta es la única solución que me ayudó a post a null valueacceder a una propiedad en requestBody que, de lo contrario, se ignoraba.
Shubhral
Sé que llego tarde, pero ¿qué hay jsonParams.put("code", some_code);en la tercera línea?
Naveen Niraula
81

En Retrofit2 , cuando desee enviar sus parámetros en bruto, debe usar Scalars .

Primero agregue esto en su 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", "[email protected]");
            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) {
    }
}
Jonathan Nolasco Barrientos
fuente
10
El truco aquí es el adaptador escalar antes de Gson, de lo contrario, Gson envolverá su JSON serializado manualmente en una cadena.
TWiStErRob
2
jonathan-nolasco-barrientos tienes que cambiar .baseUrl (ApiInterface.ENDPOINT) a .baseUrl (ApiInterface.URL_BASE)
Milad Ahmadi
2
Cuando lo usas GsonConverterFactory, .toString()no es necesario. Puede declarar Call<User> getUser(@Body JsonObject body);usando en JsonObjectlugar de JSONObjecty pasar el paramObjectdirectamente. Funcionará bien.
Igor de Lorenzi
1
@IgordeLorenzi resuelve mi problema, ya que estoy usando el arranque de primavera para recuperar el json solo JsonObject de gson funciona bien
haidarvm
1
@IgordeLorenzi ¿Hay alguna diferencia sobre cuál es mejor utilizar JSONObject o JsonObject con escalares?
Sumit Shukla
44

Usar JsonObjectes como es:

  1. Crea tu interfaz así:

    public interface laInterfaz{ 
        @POST("/bleh/blah/org")
        void registerPayer(@Body JsonObject bean, Callback<JsonObject> callback);
    }
    
  2. Haga el JsonObject de acuerdo con la estructura 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. Llamar 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 desorden de la clase. Esto es mucho más limpio.

superusuario
fuente
1
¿Qué sucede si no quiero enviar un valor específico en la clase jsonobject? ¿Qué anotación puedo usar arriba verificable para eso?
Ali Gürelli el
1
Como puede ver el ejemplo anterior ... JsonObject como es un objeto, no utiliza ninguna anotación. En su caso, si no desea enviar un valor específico, es posible que simplemente no lo agregue como una propiedad ...
superUser
1
Quiero decir que no quiero enviar el valor que se declara en la clase. Por cierto, solucioné el problema. Había una anotación para ese nombre que se expone.
Ali Gürelli el
2
Esta es la forma más flexible. Puede construir su objeto json incluso si no sabe cuántos campos tendrá o incluso si no sabe que me llaman +1
Stoycho Andreev
1
recibo un error Los métodos de servicio no pueden devolver nulo. para el método APIServices.signUpUser
Erum
11

Me gusta especialmente la sugerencia de Jake de la TypedStringsubclase anterior . De hecho, podría crear una variedad de subclases basadas en los tipos de datos POST que planea impulsar, 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 Retrofit ...

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

... pero el uso de una subclase es más obviamente autodocumentado.

@POST("/json/foo/bar")
Response fubar( @Body TypedJsonString jsonBody ) ;
ancho de banda cero
fuente
1
Salvó el día con un ejemplo claro usando TypedJsonString de la sugerencia de JW
miroslavign
10

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) haz 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 a partir del esquema Json 2 pojo

Recuerde
-Idioma de destino: Java -Tipo de fuente: JSON -Estilo de anotación: Gson -seleccione Incluir getters y setters -también puede seleccionar Permitir propiedades adicionales

http://www.jsonschema2pojo.org/

4) hacer interfaz para llamadas api

    public interface Webservices {

@POST("ApiUrlpath")
    Call<ResponseBean> ApiName(@Body JsonObject jsonBody);

}

Si tiene parámetros 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) Llama a Api así

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();
    }
}
Adil
fuente
9

Descubrí que cuando usa un objeto compuesto como @Bodyparams, no podría funcionar bien con el Retrofit GSONConverter(bajo el supuesto de que está usando eso). Debe usar JsonObjecty no JSONObjectcuando trabaja con eso, agrega NameValueParamssin ser detallado al respecto, solo puede ver eso si agrega otra dependencia de interceptor de registro y otras travesuras.

Entonces, lo que encontré es el mejor enfoque para abordar esto RequestBody. Convierte su objeto RequestBodycon una simple llamada API y lo inicia. En mi caso estoy convirtiendo un mapa:

   val map = HashMap<String, Any>()
        map["orderType"] = orderType
        map["optionType"] = optionType
        map["baseAmount"] = baseAmount.toString()
        map["openSpotRate"] = openSpotRate.toString()
        map["premiumAmount"] = premiumAmount.toString()
        map["premiumAmountAbc"] = premiumAmountAbc.toString()
        map["conversionSpotRate"] = (premiumAmountAbc / premiumAmount).toString()
        return RequestBody.create(MediaType.parse("application/json; charset=utf-8"), JSONObject(map).toString())

y esta es la llamada:

 @POST("openUsvDeal")
fun openUsvDeal(
        @Body params: RequestBody,
        @Query("timestamp") timeStamp: Long,
        @Query("appid") appid: String = Constants.APP_ID,
): Call<JsonObject>
usuario de peresis
fuente
2
Bueno, esto me ayudó después de buscar en Google durante la noche.
W4R10CK
8

Agregue ScalarsConverterFactory para actualizar:

en gradle:

implementation'com.squareup.retrofit2:converter-scalars:2.5.0'

su modificación:

retrofit = new Retrofit.Builder()
            .baseUrl(WEB_DOMAIN_MAIN)
            .addConverterFactory(ScalarsConverterFactory.create())
            .addConverterFactory(GsonConverterFactory.create(gson))
            .build();

cambie el parámetro @Body de su interfaz de llamada a String, no olvide agregar @Headers("Content-Type: application/json"):

@Headers("Content-Type: application/json")
@POST("/api/getUsers")
Call<List<Users>> getUsers(@Body String rawJsonString);

ahora puedes publicar json sin formato.

ali-star
fuente
6

Puede usar hashmap si no desea crear una clase pojo para cada llamada a la API.

HashMap<String,String> hashMap=new HashMap<>();
        hashMap.put("email","[email protected]");
        hashMap.put("password","1234");

Y luego enviar así

Call<JsonElement> register(@Body HashMap registerApiPayload);
jatin rana
fuente
5

usa siguiente 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 pásalo a url

@Body RequestBody key
Mahesh Pandit
fuente
4

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

umair151
fuente
También estaba cometiendo el mismo error: p
Mehtab Ahmed
4

Basado en 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<String, Object> data;
    Map<String, Object> 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 anotación @Bodypuede pasar a Retrofit.

wjploop
fuente
4

Si no desea crear clases adicionales o usarlas JSONObject, puede usar a HashMap.

Interfaz de actualización:

@POST("/rest/registration/register")
fun signUp(@Body params: HashMap<String, String>): Call<ResponseBody>

Llamada:

val map = hashMapOf(
    "username" to username,
    "password" to password,
    "firstName" to firstName,
    "surname" to lastName
)

retrofit.create(TheApi::class.java)
     .signUp(map)
     .enqueue(callback)
SoftDesigner
fuente
3

Cosas necesarias para enviar json sin formato en Retrofit.

1) Asegúrese de agregar el siguiente encabezado y eliminar cualquier otro encabezado duplicado. Desde entonces, en la documentación oficial de Retrofit mencionan específicamente:

Tenga en cuenta que los encabezados no se sobrescriben entre sí. Todos los encabezados con el mismo nombre se incluirán en la solicitud.

@Headers({"Content-Type: application/json"})

2) a. Si está utilizando una fábrica de convertidores, puede pasar su json como String, JSONObject, JsonObject e incluso POJO. También lo he comprobado, tenerlo ScalarConverterFactoryno es necesario solo GsonConverterFactoryhace el trabajo.

@POST("/urlPath")
@FormUrlEncoded
Call<Response> myApi(@Header("Authorization") String auth, @Header("KEY") String key, 
                     @Body JsonObject/POJO/String requestBody);

2) b. Si NO está utilizando ninguna fábrica de convertidores, DEBE utilizar RequestBody de okhttp3 como dice la documentación de Retrofit:

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

RequestBody requestBody=RequestBody.create(MediaType.parse("application/json; charset=utf-8"),jsonString);

@POST("/urlPath")
@FormUrlEncoded
Call<Response> myApi(@Header("Authorization") String auth, @Header("KEY") String key, 
                 @Body RequestBody requestBody);

3) ¡Éxito!

Darshan Miskin
fuente
2

Esto es lo que me funciona para la versión actual de retrofit 2.6.2 ,

En primer lugar, debemos agregar un convertidor de Scalars a la lista de nuestras dependencias de Gradle, que se encargaría de convertir los objetos java.lang.String en cuerpos de solicitud de texto / sin formato,

implementation'com.squareup.retrofit2:converter-scalars:2.6.2'

Luego, necesitamos pasar una fábrica de convertidores a nuestro generador de Retrofit. Más tarde le dirá a Retrofit cómo convertir el parámetro @Body pasado al servicio.

private val retrofitBuilder: Retrofit.Builder by lazy {
    Retrofit.Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(ScalarsConverterFactory.create())
        .addConverterFactory(GsonConverterFactory.create())
}

Nota: en mi generador de actualizaciones tengo dos convertidores Gsony Scalarspuedes usar ambos, pero para enviar el cuerpo de Json debemos enfocarnos, Scalarsasí que si no necesitas Gsonquitarlo

Luego, el servicio de actualización con un parámetro de cuerpo de cadena.

@Headers("Content-Type: application/json")
@POST("users")
fun saveUser(@Body   user: String): Response<MyResponse>

Luego crea el cuerpo JSON

val user = JsonObject()
 user.addProperty("id", 001)
 user.addProperty("name", "Name")

Llama a tu servicio

RetrofitService.myApi.saveUser(user.toString())
Jimale Abdi
fuente
2

✅✅✅✅✅✅✅✅✅✅✅✅ Solución de trabajo ✅✅✅✅✅✅✅✅✅✅✅✅

Durante la creación OkHttpClient , se usará para la actualización.

agregue un interceptor como este.

 private val httpClient = OkHttpClient.Builder()
        .addInterceptor (other interceptors)
        ........................................

        //This Interceptor is the main logging Interceptor
        .addInterceptor { chain ->
            val request = chain.request()
            val jsonObj = JSONObject(Gson().toJson(request))

            val requestBody = (jsonObj
            ?.getJSONObject("tags")
            ?.getJSONObject("class retrofit2.Invocation")
            ?.getJSONArray("arguments")?.get(0) ?: "").toString()
            val url = jsonObj?.getJSONObject("url")?.getString("url") ?: ""

            Timber.d("gsonrequest request url: $url")
            Timber.d("gsonrequest body :$requestBody")

            chain.proceed(request)
        }

        ..............
        // Add other configurations
        .build()

Ahora el cuerpo URL y solicitar su reequipamiento de cada llamada se registra en Logcat. Filtrar por"gsonrequest"

erluxman
fuente
1

Intenté esto: cuando esté creando su instancia de Retrofit, agregue esta fábrica de convertidores al generador de retrofit:

gsonBuilder = new GsonBuilder().serializeNulls()     
your_retrofit_instance = Retrofit.Builder().addConverterFactory( GsonConverterFactory.create( gsonBuilder.create() ) )
Arman Ramezanzadeh
fuente
1

Resolvió mi problema basado en la respuesta de TommySM (ver anterior). Pero no necesitaba iniciar sesión, utilicé Retrofit2 para probar la API GraphQL https de esta manera:

  1. Definí mi clase BaseResponse con la ayuda de anotaciones json (import jackson.annotation.JsonProperty).

    public class MyRequest {
        @JsonProperty("query")
        private String query;
    
        @JsonProperty("operationName")
        private String operationName;
    
        @JsonProperty("variables")
        private String variables;
    
        public void setQuery(String query) {
            this.query = query;
        }
    
        public void setOperationName(String operationName) {
            this.operationName = operationName;
        }
    
        public void setVariables(String variables) {
            this.variables = variables;
        }
    }
  2. Definió el procedimiento de llamada en la interfaz:

    @POST("/api/apiname")
    Call<BaseResponse> apicall(@Body RequestBody params);
  3. Llamado apicall en el cuerpo de la prueba: Cree una variable de tipo MyRequest (por ejemplo, "myLittleRequest").

    Map<String, Object> jsonParams = convertObjectToMap(myLittleRequest);
    RequestBody body = 
         RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"),
                        (new JSONObject(jsonParams)).toString());
    response = hereIsYourInterfaceName().apicall(body).execute();
Natalya Shatalova
fuente
0

Para mayor claridad sobre las respuestas dadas aquí, así es como puede usar las funciones de extensión. Esto es solo si está utilizando Kotlin

Si está utilizando com.squareup.okhttp3:okhttp:4.0.1los métodos más antiguos para crear objetos de MediaType y RequestBody han quedado en desuso y no se pueden usar en Kotlin .

Si desea usar las funciones de extensión para obtener un objeto MediaType y un objeto ResponseBody de sus cadenas, primero agregue las siguientes líneas a la clase en la que espera usarlas.

import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.toRequestBody

Ahora puede obtener directamente un objeto de MediaType de esta manera

val mediaType = "application/json; charset=utf-8".toMediaType()

Para obtener un objeto de RequestBody, primero convierta el JSONObject que desea enviar a una cadena de esta manera. Tienes que pasarle el objeto mediaType.

val requestBody = myJSONObject.toString().toRequestBody(mediaType)
Venganza
fuente
0

Quería comparar la velocidad de la volea y la actualización para enviar y recibir datos que escribí debajo del código (para la parte de actualización)

primera dependencia:

dependencies {
     implementation 'com.squareup.retrofit2:retrofit:2.4.0'
     implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
}

Luego interfaz:

 public interface IHttpRequest {

    String BaseUrl="https://example.com/api/";

    @POST("NewContract")
    Call<JsonElement> register(@Body HashMap registerApiPayload);
}

y una función para establecer parámetros para publicar datos en el servidor (en MainActivity):

private void Retrofit(){

    Retrofit retrofitRequest = new Retrofit.Builder()
            .baseUrl(IHttpRequest.BaseUrl)
            .addConverterFactory(GsonConverterFactory.create())
            .build();

    // set data to send
    HashMap<String,String> SendData =new HashMap<>();
    SendData.put("token","XYXIUNJHJHJHGJHGJHGRTYTRY");
    SendData.put("contract_type","0");
    SendData.put("StopLess","37000");
    SendData.put("StopProfit","48000");

    final IHttpRequest request=retrofitRequest.create(IHttpRequest.class);

    request.register(SendData).enqueue(new Callback<JsonElement>() {
        @Override
        public void onResponse(Call<JsonElement> call, Response<JsonElement> response) {
            if (response.isSuccessful()){
                Toast.makeText(getApplicationContext(),response.body().toString(),Toast.LENGTH_LONG).show();
            }
        }

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

        }
    });

}

Y encontré Retrofit más rápido que volea en mi caso.

Liam
fuente