Como POSTAR JSON inteiro bruto no corpo de uma solicitação de Retrofit?

284

Esta pergunta pode ter sido feita antes, mas não, não foi definitivamente respondida. Como exatamente postamos JSON inteiro bruto dentro do corpo de uma solicitação de Retrofit?

Veja pergunta semelhante aqui . Ou é esta resposta correta que deve ser codificado em URL e passado como um campo ? Eu realmente espero que não, pois os serviços aos quais estou me conectando esperam apenas JSON bruto no corpo do post. Eles não estão configurados para procurar um campo específico para os dados JSON.

Eu só quero esclarecer isso com os restperts de uma vez por todas. Uma pessoa respondeu para não usar o Retrofit. O outro não tinha certeza da sintaxe. Outro pensa que sim, isso pode ser feito, mas apenas se o formulário for codificado em URL e colocado em um campo (isso não é aceitável no meu caso). Não, não consigo codificar novamente todos os serviços do meu cliente Android. E sim, é muito comum em grandes projetos publicar JSON bruto em vez de passar o conteúdo JSON como valores de propriedade do campo. Vamos acertar e seguir em frente. Alguém pode apontar para a documentação ou exemplo que mostra como isso é feito? Ou forneça uma razão válida pela qual isso não pode / não deve ser feito.

ATUALIZAÇÃO: Uma coisa que posso dizer com 100% de certeza. Você pode fazer isso no Google Volley. Está embutido. Podemos fazer isso no Retrofit?

user3243335
fonte
7
O post de Jake Wharton está correto! Marcar como resposta!
edotassi
1
Você pode usar o jsonObject melhor.
SuperUser 27/09/15
funciona perfeitamente RequestBodyassim -> RequestBody body = RequestBody.create(MediaType.parse("text/plain"), text);para obter respostas detalhadas futurestud.io/tutorials/…
Kidus Tekeste

Respostas:

461

A @Bodyanotação define um único corpo de solicitação.

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

Como o Retrofit usa o Gson por padrão, as FooRequestinstâncias serão serializadas como JSON como o único corpo da solicitação.

public class FooRequest {
  final String foo;
  final String bar;

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

Ligando com:

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

Produzirá o seguinte corpo:

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

Os documentos do Gson têm muito mais informações sobre como a serialização de objetos funciona.

Agora, se você realmente deseja enviar o JSON "bruto" como o seu próprio corpo (mas use o Gson para isso!), Ainda poderá usar TypedInput:

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

TypedInput é definido como "Dados binários com um tipo mime associado". Há duas maneiras de enviar facilmente dados brutos com a declaração acima:

  1. Use TypedByteArray para enviar bytes não processados ​​e o 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. Subclasse TypedString para criar uma TypedJsonStringclasse:

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

    E, em seguida, use uma instância dessa classe semelhante ao nº 1.

Jake Wharton
fonte
5
Muito bem, no entanto, existe alguma maneira de fazer isso sem fazer os pojos?
SuperUser
28
Isso não está funcionando no retrofit 2. As classes TypedInput e TypedString foram removidas.
Ahmed Hegazy
2
@jakewharton O que podemos fazer TypedStringdesde que foi removido?
Jared Burrows
12
Para o Retrofit2, você pode usar RequestBodypara criar um corpo bruto.
bnorm
4
Estou recebendo essa exceção #java.lang.IllegalArgumentException: Unable to create @Body converter for class MatchAPIRequestBody (parameter #1)
Shajeel Afzal
154

Em vez de classes, também podemos usar diretamente o HashMap<String, Object>para enviar parâmetros do corpo, por exemplo

interface Foo {
  @POST("/jayson")
  FooResponse postJson(@Body HashMap<String, Object> body);
}
aprendiz
fonte
2
Nesse momento, você pode criar um mapa Hash como o HashMap <String, Object>; pode ser possível criar matrizes e objetos JSON complexos.
aluno
2
Isso é excelente se você não quiser ser vinculado a um POJO de algum tipo.
Tim
2
@Nil você não pode enviar o objeto json usando o retrofit ... você adere ao pojo ou a minha resposta ... essa é a natureza do retrofit. .
aluno
5
Eu fico IllegalArgumentException: Unable to create @Body converter for java.util.HashMap<java.lang.String, java.lang.Object>com Moshi. Acho Gson é necessária para que isso funcione
OSRL
2
Se estiver usando o Kotlin, use um hashmap de <String, Any>
peresisUser
148

Sim, eu sei que é tarde, mas alguém provavelmente se beneficiaria com isso.

Usando o Retrofit2:

Encontrei esse problema na noite passada ao migrar do Volley para o Retrofit2 (e, como afirma o OP, isso foi incorporado ao Volley JsonObjectRequest), e embora a resposta de Jake seja a correta para o Retrofit1.9 , o Retrofit2 não possui TypedString.

Meu caso exigia o envio de um Map<String,Object>que pudesse conter alguns valores nulos, convertido em um JSONObject (que não voa com @FieldMap, nem caracteres especiais, alguns são convertidos), portanto, seguindo a dica @bnorms, e conforme declarado por Square :

Um objeto pode ser especificado para uso como um corpo de solicitação HTTP com a anotação @Body.

O objeto também será convertido usando um conversor especificado na instância Retrofit. Se nenhum conversor for adicionado, apenas RequestBody poderá ser usado.

Portanto, esta é uma opção usando RequestBodye ResponseBody:

Na sua interface, use @BodycomRequestBody

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

No seu ponto de chamada, crie um RequestBody, indicando seu MediaType, e usando JSONObject para converter seu mapa no formato adequado:

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 isso ajude alguém!


Uma versão elegante do Kotlin acima, para permitir abstrair os parâmetros da conversão JSON no restante do código do aplicativo:

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
fonte
2
Sim, estou vendo muitas respostas complicadas por todo o lado. Se você estiver usando o Retrofit2 e quiser fazer vôlei JsonObjectRequest, tudo o que você precisa fazer é isso. Boa resposta.
VicVu 17/05
2
A atualização adiciona uma chave chamada "nameValuePairs" na parte superior de todos os objetos json. Como posso remover esta @TommySM
NR 5
1
Obrigado! Isso resolveu meu problema. Agora eu posso enviar JSONObject diretamente sem criar POJOs.
Erfan GLMPR 28/03
1
Esta é a única solução que me ajudou post a null valuea acessar uma propriedade no requestBody que, de outra forma, estava sendo ignorada.
Shubhral
Eu sei que estou atrasado, mas o que está jsonParams.put("code", some_code);na terceira linha?
Naveen Niraula
81

No Retrofit2 , quando você deseja enviar seus parâmetros em bruto, deve usar escalares .

adicione primeiro no seu 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'

Sua interface

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

}

Atividade

   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
fonte
9
O truque aqui é o adaptador escalar antes do Gson, caso contrário, o Gson envolverá seu JSON serializado manualmente em uma String.
TWIStErRob
2
jonathan-Nolasco-Barrientos você tem que mudar .baseUrl (ApiInterface.ENDPOINT) para .baseUrl (ApiInterface.URL_BASE)
Milad Ahmadi
2
Quando você usa GsonConverterFactory, o .toString()não é necessário. Você pode declarar Call<User> getUser(@Body JsonObject body);usando em JsonObjectvez de JSONObjecte passar o paramObjectdiretamente. Funcionará muito bem.
Igor de Lorenzi
1
@IgordeLorenzi resolver o meu problema, desde que eu estou usando bota primavera para recuperar o json única JSONObject de Gson funciona bem
haidarvm
1
@IgordeLorenzi Existe alguma diferença em qual JSONObject ou JsonObject é melhor para usar com escalares.
Sumit Shukla
44

Usando JsonObjecté da maneira que é:

  1. Crie sua interface assim:

    public interface laInterfaz{ 
        @POST("/bleh/blah/org")
        void registerPayer(@Body JsonObject bean, Callback<JsonObject> callback);
    }
  2. Faça o JsonObject de acordo com a estrutura 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. Ligue para o serviço:

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

E é isso! Na minha opinião pessoal, é muito melhor do que fazer pojos e trabalhar com a bagunça da classe. Isso é muito mais limpo.

superusuário
fonte
1
E se eu não quiser enviar um valor specif na classe jsonobject. qual anotação posso usar acima verificável para isso?
Ali Gürelli
1
Como você pode ver no exemplo acima ... O JsonObject, por ser um objeto, não usa nenhuma anotação. No seu caso, se você não quiser enviar valor específico, que você pode simplesmente não adicioná-lo como uma propriedade ...
superusuário
1
Quero dizer, não quero enviar o valor declarado na classe. Btw eu corrigi o problema. Havia uma anotação para o nome que está exposto.
Ali Gürelli
2
Esta é a maneira mais flexível. Você pode construir o seu objeto JSON, mesmo se você não sabe quantos campos você terá ou mesmo se você não sabem que nomes +1 de mim
Stoycho Andreev
1
estou recebendo erro Os métodos de serviço não podem retornar nulos. para APIServices.signUpUser método
Erum
11

Eu particularmente gosto da sugestão de Jake da TypedStringsubclasse acima . Você pode realmente criar uma variedade de subclasses com base nos tipos de dados do POST que planeja enviar, cada um com seu próprio conjunto personalizado de ajustes consistentes.

Você também tem a opção de adicionar uma anotação de cabeçalho aos métodos JSON POST na sua API Retrofit…

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

... mas usar uma subclasse é mais obviamente auto-documentado.

@POST("/json/foo/bar")
Response fubar( @Body TypedJsonString jsonBody ) ;
zerobandwidth
fonte
1
Guardar o dia com um claro exemplo usando TypedJsonString de sugestão JW
miroslavign
10

1) Adicionar dependências

 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) faça a classe 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) criar classes de bean a partir do esquema Json 2 pojo

Lembre-se da
linguagem -Target: Java -Tipo de fonte: JSON -Estilo de anotação: Gson -select Incluir getters e setters -também pode selecionar Permitir propriedades adicionais

http://www.jsonschema2pojo.org/

4) faça a interface para a api chamando

    public interface Webservices {

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

}

se você tiver parâmetros de dados de formulário, adicione a linha abaixo

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

Outra maneira para o parâmetro form-data, verifique este link

5) faça o JsonObject para passar para o corpo 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) Ligue para a Api assim

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
fonte
9

Descobri que quando você usa um objeto composto como @Bodyparâmetro, ele não funciona bem com o Retrofit GSONConverter(sob a suposição de que você esteja usando isso). Você precisa usar JsonObjecte não JSONObjectao trabalhar com isso, ele adiciona NameValueParamssem ser detalhado - só é possível ver que se você adicionar outra dependência do interceptador de log e outras travessuras.

Então, o que eu achei a melhor abordagem para resolver isso está usando RequestBody. Você transforma seu objeto RequestBodycom uma simples chamada de API e o inicia. No meu caso, estou convertendo um 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())

e esta é a chamada:

 @POST("openUsvDeal")
fun openUsvDeal(
        @Body params: RequestBody,
        @Query("timestamp") timeStamp: Long,
        @Query("appid") appid: String = Constants.APP_ID,
): Call<JsonObject>
peresisUser
fonte
2
Bem, isso me ajudou depois de pesquisar durante a noite.
W4R10CK 25/08/19
8

Adicione ScalarsConverterFactory à atualização:

em gradle:

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

seu retrofit:

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

altere o parâmetro @Body da interface de chamada para String, não se esqueça de adicionar @Headers("Content-Type: application/json"):

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

agora você pode postar json bruto.

ali-estrela
fonte
6

Você pode usar o hashmap se não desejar criar a classe pojo para cada chamada da API.

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

E então envie assim

Call<JsonElement> register(@Body HashMap registerApiPayload);
jatin rana
fonte
4

Depois de tanto esforço, descobriu que a diferença básica é que você precisa enviar o parâmetro em JsonObjectvez de JSONObjectcomo.

umair151
fonte
Eu também estava cometendo o mesmo erro: p
Mehtab Ahmed
4

use o seguinte 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());

e passe para url

@Body RequestBody key
Mahesh Pandit
fonte
4

Com base na resposta principal, tenho uma solução para não precisar criar POJOs para cada solicitação.

Exemplo, quero postar este JSON.

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

então, crio uma classe comum 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, quando eu preciso de um json

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

A solicitação marcada como anotação @Bodypode passar para Retrofit.

wjploop
fonte
4

Se você não deseja criar classes extras ou usar, JSONObjectpode usar a HashMap.

Interface de modernização:

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

Ligar:

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
fonte
3

Itens necessários para enviar json bruto no Retrofit.

1) Certifique-se de adicionar o cabeçalho a seguir e remover qualquer outro cabeçalho duplicado. Visto que, na documentação oficial da Retrofit, eles mencionam especificamente

Observe que os cabeçalhos não se substituem. Todos os cabeçalhos com o mesmo nome serão incluídos na solicitação.

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

2) a. Se você estiver usando uma fábrica de conversores, poderá passar seu json como uma String, JSONObject, JsonObject e até um POJO. Também verifiquei, ScalarConverterFactorynão é necessário apenas GsonConverterFactoryfazer o trabalho.

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

2) b. Se você NÃO estiver usando nenhuma fábrica de conversores, DEVE usar o RequestBody do okhttp3 como a documentação do Retrofit diz:

O objeto também será convertido usando um conversor especificado na instância Retrofit. Se nenhum conversor for adicionado, apenas RequestBody poderá ser usado.

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) Sucesso !!

Darshan Miskin
fonte
2

É isso que funciona para a versão atual do retrofit 2.6.2 ,

Primeiro, precisamos adicionar um conversor de escalares à lista de nossas dependências Gradle, que cuidaria da conversão de objetos java.lang.String em corpos de solicitação de texto / sem formatação,

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

Então, precisamos passar uma fábrica de conversores para o nosso construtor Retrofit. Mais tarde, informará à Retrofit como converter o parâmetro @Body passado para o serviço.

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

Nota: No meu construtor de retrofit, tenho dois conversores Gsone Scalarsvocê pode usá-los, mas para enviar o corpo de Json, precisamos nos concentrar, Scalarsportanto, se você não precisar Gsonremovê-lo

Em seguida, atualize o serviço com um parâmetro de corpo String.

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

Em seguida, crie o corpo JSON

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

Ligue para o seu serviço

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

✅✅✅✅✅✅✅✅✅✅✅✅ Solução de Trabalho ✅✅✅✅✅✅✅✅✅✅✅✅

Ao criar OkHttpClient isso, será usado para o Retrofit.

adicione um 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()

Agora URL e solicitar corpo todas as suas Retrofit de chamada será registrado no Logcat. Filtre por"gsonrequest"

erluxman
fonte
1

Eu tentei o seguinte: Quando você estiver criando sua instância de Retrofit, adicione esta fábrica de conversores ao construtor de retrofit:

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

Resolvi o meu problema com base na resposta do TommySM (veja anterior). Mas eu não precisava fazer login, usei o Retrofit2 para testar a API https GraphQL da seguinte forma:

  1. Definiu minha classe BaseResponse com a ajuda de anotações 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. Definiu o procedimento de chamada na interface:

    @POST("/api/apiname")
    Call<BaseResponse> apicall(@Body RequestBody params);
  3. Chamado apicall no corpo do teste: Crie uma variável do tipo MyRequest (por exemplo "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
fonte
0

Para mais clareza nas respostas fornecidas aqui, é assim que você pode usar as funções de extensão. Isso é apenas se você estiver usando o Kotlin

Se você estiver usando com.squareup.okhttp3:okhttp:4.0.1os métodos mais antigos de criação de objetos do MediaType e RequestBody , foi preterido e não pode ser usado no Kotlin .

Se você deseja usar as funções de extensão para obter um objeto MediaType e um objeto ResponseBody de suas seqüências, primeiro adicione as seguintes linhas à classe na qual você espera usá-las.

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

Agora você pode obter diretamente um objeto do MediaType dessa maneira

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

Para obter um objeto RequestBody, primeiro converta o JSONObject que você deseja enviar para uma string dessa maneira. Você precisa passar o objeto mediaType para ele.

val requestBody = myJSONObject.toString().toRequestBody(mediaType)
Devenom
fonte
0

Eu queria comparar a velocidade do vôlei e o retrofit para enviar e receber dados que escrevi abaixo do código (para parte do retrofit)

primeira dependência:

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

Então faça a interface:

 public interface IHttpRequest {

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

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

e uma função para definir parâmetros para postar dados no servidor (In 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) {

        }
    });

}

E eu encontrei o Retrofit mais rápido que o vôlei no meu caso.

Liam
fonte