Retrofit - Get Raw non JSON Array - android

I am using Retrofit2 for the first time and have a problem to get a simple Array in non JSON format.
Error: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 3 path $[0]
This means its not an JSON Object since it does not start with "{"
I tried adding the ScalarsConverter but it doesent seems to work.
Api: https://chasing-coins.com/api/v1/coins
Interface:
public interface Retro_coins {
#GET("api/v1/coins")
Call<List<Coinlist>> getCoinlist();
}
Class:
public class Coinlist {
private List coinlist;
public List getCoinlist() {
return coinlist;
}
}
Retrofit initialization and call:
String API_BASE_URL = "https://chasing-coins.com/";
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addConverterFactory(ScalarsConverterFactory.create())
;
Retrofit retrofit = builder.client(httpClient.build()).build();
Retro_coins client = retrofit.create(Retro_coins.class);
// Fetch list
Call<List<Coinlist>> call =
client.getCoinlist();
// Execute the call asynchronously. Get a positive or negative callback.
call.enqueue(new Callback<List<Coinlist>>() {
#Override
public void onResponse(Call<List<Coinlist>> call, Response<List<Coinlist>> response) {
// The network call was a success and we got a response
Log.w("Yes", response.toString());
}
#Override
public void onFailure(Call<List<Coinlist>> call, Throwable t) {
Log.w("no", t.toString());
}
});
Thanks!

When you are using private List coinlist;, Gson expects the object to be
{
"coinlist":"[]"
}
where as what you are providing is just
["String","String","String"]
furthermore when you use Call<List<Coinlist>> you are expecting the data to be
[
{
"coinlist":"[]"
}
]
Just change your call from Call<List<Coinlist>> to Call<List<String>>. That should fix your problem. Let me know if you need more clarification

Your request Returning String. So you need to Change the Response to String or Need to change your request Call to String.

Related

Retrofit causing Expected BEGIN_OBJECT but was STRING at line 1 column 153 path $.joining

I am using a REST API created by me using SpringBoot.When I tried tested using Postman I am getting a valid JSON,but Retrofit causes this issue.
I have checked the ModelClass and it is not causing an issue.
I have other POST methods which are working absolutely fine but an issue is occuring with GET method.
The Retrofit is as follows:
public class RetrofitService {
static Gson gson = new GsonBuilder()
.setLenient()
.create();
static OkHttpClient client = new OkHttpClient();
//addConverterFactory(GsonConverterFactory.create(gson))
private static Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://Location/api/v1/")
.client(client)
//.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
public static Retrofit createService() {
return retrofit;
}
}
The Repository is:
public class HomeFragRepository {
private Networking networking;
private MutableLiveData<EmployeeClass> mutableUserDetails;
public HomeFragRepository() {
networking= RetrofitService.createService().create(Networking.class);
}
public MutableLiveData<EmployeeClass> getUserHomeDetails(Long userId){
mutableUserDetails=new MutableLiveData<>();
networking.employeeHomeDetails(userId).enqueue(new Callback<EmployeeClass>() {
#Override
public void onResponse(Call<EmployeeClass> call, Response<EmployeeClass> response) {
if(response.isSuccessful()){
Log.i("Response",response.body().toString());
mutableUserDetails.setValue(response.body());
}
else{
try {
EmployeeClass employeeClass=new Gson().fromJson(response.errorBody().string(),
EmployeeClass.class);
Log.i("HelloLogin",employeeClass.getMessage());
mutableUserDetails.setValue(employeeClass);
} catch (IOException e) {
e.printStackTrace();
}
}
}
#Override
public void onFailure(Call<EmployeeClass> call, Throwable t) {
t.printStackTrace();
}
});
return mutableUserDetails;
}
}
The Employee Model Class is same in Spring and Android so it is not causing any issue.
The GET Method in Spring is:
#RequestMapping(value = "/employee", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<EmployeeClass> getEmployee(#RequestParam(value="userId") Long userId){
EmployeeClass employeeClass=attendanceService.searchEmployee(userId);
return new ResponseEntity<>(employeeClass,HttpStatus.valueOf(employeeClass.getStatus()));
}
This is somehow producing a String instead of a JSON.
Thanks in Advance.
This usually happens when you're receiving something other than the expected response from the server.
It because because you mentioned EmployeeClass in Call so what happens is
the object block in your json response has no name so it is unable to find the object...
try to use
#RequestMapping(value = "/employee", method = RequestMethod.GET, produces =
MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<ResponseBody> getEmployee(#RequestParam(value="userId")
Long userId){
EmployeeClass employeeClass=attendanceService.searchEmployee(userId);
return new ResponseEntity<>
(employeeClass,HttpStatus.valueOf(employeeClass.getStatus()));
}
then parse json manually to get data and save it in your model
or you can try to add #Headers({"Accept: application/json"}) in Retrofit interface see if it works
#Headers({"Accept: application/json"})

Retrofit2 Code 400 Bad Request

I'm trying to do a POST, but its returning me a error :
com.google.gson.stream.MalformedJsonException: Use
JsonReader.setLenient(true) to accept malformed JSON at line 1 column
1 path $
My Call:
#POST("BuscaPontos")
Call<PontuacaoModel> postPontuacao(#Body PontuacaoModel model);
And my Webservice consum:
try
{
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(URL_BUSCAR_CIDADE)
.addConverterFactory(GsonConverterFactory.create(new Gson()))
.build();
PontuacaoModel model = new PontuacaoModel();
model.setNome("Juina");
model.setEstado("Mato Grosso");
CallService.Pontuacao callService = retrofit.create(CallService.Pontuacao.class);
Call<PontuacaoModel> requestService = callService.postPontuacao(model);
requestService.enqueue(new Callback<PontuacaoModel>() {
#Override
public void onResponse(Call<PontuacaoModel> call, Response<PontuacaoModel> response) {
if(response.isSuccessful())
{
String i = response.message().toString();
}
}
#Override
public void onFailure(Call<PontuacaoModel> call, Throwable t) {
String i = t.toString();
}
});
}
catch (Exception ex)
{
}
Whats is wrong ?
I don't see a line in your code where you add client during initializing retrofit:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(URL_BUSCAR_CIDADE)
.client() // add a client instance here, e.g. OkHttpClient
.addConverterFactory(GsonConverterFactory.create(new Gson()))
.build();
This is the issue with your response from server, that may not be correct format. Please install a tool called postman form here.
Use this tool to check whether the response is correct before do some coding.

Do I need to make new interfaces every time in Retrofit 2

I want to ask that do I need to create new Interfaces for every POST GET request I make which have different URL .
For ex
I made 1 interface for register and other for Login other for getting Friends. Cant I just make 1 general post and get method where I can send URL , params to send and record response?
No you don't need to create new interface or new client for each request!
Inside a interface you can create multiple method as you want and as your requirement.
For Login and fro Registration method name will be different, your parameter will not same. So you can create method as you need.
//When Base Url like "http://exmaple.com/"
#GET("Service/registration")
Call<RegResult> getRegistered(#Query("name") String name,
#Query("email") String email,
#Query("dob") String dob,
#Query("name") String name
);
#GET("Service/login")
Call<LoginResult> getLogin(#Query("username") String username,
#Query("pass") String pass
);
#GET("Service/profile")
Call<ProfileResult> getProfile(#Query("userid") String userid
);
You can also use same client because your base url is same.
If base url is diffrent you can also use same client like this..
public class ApiClient {
private static Retrofit retrofit = null;
public static Retrofit getClient(String base_url) {
if (retrofit==null) {
retrofit = new Retrofit.Builder()
.baseUrl(base_url)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
Now you can set different base url.
Creating object of interface...
String BASE_URL = "http://exmaple.com/";
ApiInterface apiService = ApiClient.getClient(BASE_URL).create(ApiInterface.class);
Calling method..
String user_id = "1";
Call< ProfileResult > call = apiService.getProfile(user_id);
Getting result
call.enqueue(new Callback< ProfileResult >() {
#Override
public void onResponse(Call< ProfileResult >call, Response< ProfileResult > response) {
Profile profile = response.body().getResults();
}
#Override
public void onFailure(Call< ProfileResult >call, Throwable t) {
// Log error here since request failed
Log.e(TAG, t.toString());
}
});
Hop you got your answer .... for farther query fill free to ask...

Receiving response body in Retrofit2 but onResponse is not getting called

I am receiving a body from my API call but onResponse() is not getting called, here are the methods:
final Rest_manager_league rest = new Rest_manager_league();
Call<List<Root>> listCall = rest.getMLeague_conn().getLeague(x);
listCall.enqueue(new Callback<List<Root>>() {
#Override
public void onResponse(Call<List<Root>> call, Response<List<Root>> response) {
lg = response.body();
Log.d("res", "ON");
if (response.isSuccessful()){
textView.setText(lg.get(3).getStanding().get(2).getTeamName());
Log.d("s", "true");
}
}
#Override
public void onFailure(Call<List<Root>> call, Throwable t) {
Log.d("Failure", "Failed");
}
});
Here is the Retrofit interface & the service:
public interface league_Conn {
#GET("/v1/soccerseasons/{id}/leagueTable")
#Headers("X-Auth-Token:" +
"1869f69f772b40a2a12fd6eefb4e48ef ")
Call<List<Root>> getLeague(#Path("id") int id);
}
public class Rest_manager_league {
private league_Conn mleague_conn;
public league_Conn getMLeague_conn() {
if (mleague_conn == null) {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(logging).build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://api.football-data.org/")
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
mleague_conn = retrofit.create(league_Conn.class);
}
return mleague_conn;
}
}
In the logcat, onFailure() is showing up. Like so:
okhttp3 <-- END HTTP (8300 byte body) Failer :Failed
Why is onResponse() not getting called?
You are getting a response body (8300 bytes) but onFailure is getting called, because your returned body does not agree with your GSONFactory. The deserialization process did not work. You can pinpoint the problem by printing a stack trace as #yazan pointed out. Just type:
t.printStackTrace()
in onFailure().
Edit:
The error occurs because you're telling Retrofit that you're expecting a list but instead you're getting a JSON object. I took a quick look at the API that you're using and it looks like it returns a JSON object and the returned object then contains the list you're interested in accessing. Try replacing instances of List<Root> to just Root. For more help, you can also check this question:
GSON throws Expected BEGIN_ARRAY but was BEGIN_OBJECT error

Get single JSON property value from response JSON using Retrofit 2

I am using Retrofit library (version 2.0.2 as of this writing).
I am making a GET call to a service which responds a big JSON object but I am only interested in one key:value pair in it.
How can I get just that instead of writing a whole new POJO class that matches the JSON response?
Example -
{
status_code: 34,
status_message: "The resource you requested could not be found.",
...,
...
}
I need only status code value (34 here).
Please note, I am just giving an example of this JSON object here. The real one I am dealing with is huge and I care about only one key:value pair in it.
Thanks in advance.
You can refer to the following:
#GET("/files/jsonsample.json")
Call<JsonObject> readJsonFromFileUri();
and
class MyStatus{
int status_code;
}
...
Retrofit retrofit2 = new Retrofit.Builder()
.baseUrl("http://...")
.addConverterFactory(GsonConverterFactory.create())
.build();
WebAPIService apiService = retrofit2.create(WebAPIService.class);
Call<JsonObject> jsonCall = apiService.readJsonFromFileUri();
jsonCall.enqueue(new Callback<JsonObject>() {
#Override
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
String jsonString = response.body().toString();
Gson gson = new Gson();
MyStatus status = gson.fromJson(jsonString, MyStatus.class);
Log.i(LOG_TAG, String.valueOf(status.status_code));
}
#Override
public void onFailure(Call<JsonObject> call, Throwable t) {
Log.e(LOG_TAG, t.toString());
}
});
...
Debug screenshot

Categories

Resources