I'm having trouble understading Retrofi2 and the callback. Right now I'm receiving a JWT response from the back-end. The callback send me right in to the onFailure() Method and cuts off me of from the response body and I'm left with a JsonSyntaxException:
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $
I searched on the internet for a solution, but I'm confused. Some say the Gson is expecting the JSON string with openings brace. Or something about a JSON-array not being a JSON-object. How can I check this and can I modify a presumably broken Json string?
Right now the back end tells me the response is sends-off without failure. I'm also using a HttpLoggingInterceptor which seems to give me the JWT string just fine. I'm lost and don't know what to do next.
import android.content.Context;
import android.util.Base64;
import android.widget.Toast;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonSyntaxException;
import com.ssl.app.rest.User;
import com.ssl.app.rest.UserClient;
import java.io.IOException;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class LoginActivity {
protected static void login(Context context) {
String username = "jack";
String password = "9375";
String base = username + ":" +password;
String authHeader = "Basic " + Base64.encodeToString(base.getBytes(), Base64.NO_WRAP);
// Interceptor
HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient okHttpClient = new OkHttpClient.Builder().addInterceptor(httpLoggingInterceptor).build();
// Setup request
Gson gson = new GsonBuilder()
.setLenient()
.create();
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl("http://10.0.2.2:8080/")
.addConverterFactory(GsonConverterFactory.create(gson))
.client(okHttpClient);
Retrofit retrofit = builder.build();
UserClient userClient = retrofit.create(UserClient.class);
// Request
Call<User> loginResponseCall = userClient.getUser(authHeader);
// Response
loginResponseCall.enqueue(new Callback<User>() {
@Override
public void onResponse(Call<User> call, Response<User> response) {
if(response.isSuccessful()){
Toast.makeText(context,"Login Successful :) \n"+response.body(), Toast.LENGTH_LONG).show();
}
}
@Override
public void onFailure(Call<User> call, Throwable t) {
if (t instanceof IOException) {
Toast.makeText(context,"this is an actual network failure :( \n"+t, Toast.LENGTH_LONG).show();
System.out.println("this is an actual network failure\n" +t);
} else if (t instanceof JsonSyntaxException) {
Toast.makeText(context,"Gson fails to read a malformed JSON element \n"+t, Toast.LENGTH_LONG).show();
System.out.println("Gson fails to read a malformed JSON element\n" +t);
} else {
Toast.makeText(context,"conversion issue! big problem :( \n"+t, Toast.LENGTH_LONG).show();
System.out.println("conversion issue! big problem :(\n" +t);
}
}
});
}
}
public class User {
private String username;
private String password;
public User(String username, String password) {
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
Error
D/OkHttp: --> POST http://10.0.2.2:8080/token
Content-Length: 0
Authorization: Basic am9fbjoxMbM0NQ==
--> END POST (0-byte body)
D/OkHttp: <-- 200 http://10.0.2.2:8080/token (69ms)
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Type: text/plain;charset=UTF-8
Content-Length: 466
D/OkHttp: Date: Mon, 05 Dec 2022 10:23:52 GMT
Keep-Alive: timeout=60
Connection: keep-alive
eyJhbGciOiJSUzI1NiJ3.eyJpc3MiOiJzZWxmIiwic3ViIjoiam9obiIsImV4cCI6MTY3MDIzOTQzNiwiaWF0IjoxNjcwMjM1ODMyLCJzY29wZSI3InJlYWQifQ.eS8Z1Q_rYsofMDTdDhMpVxxhqElCXzHUCYEjr5_t4EC_ZFO1x1Axu045Bcy8I3zhVJUVY4borFw0qBM6GuOgy_j7vOpgeTjq_JksqDHY2jd8Yif3AVHbeBb_eJV-P2iKS34kawNEI3591A7-ZqoDYveCBKqpMU1MkWL2vfWkkcat_8EroeKQCcLRyCYhkTb9Ev2_rH8Zp8wWaNs6pPkfysV0OGJX171fKGdB5pZ5hZsjwzxDMS8jLFANNGz6rIT4jiaz0apiARF86SjPFOHKM4GNrklfa2LZEr_3xyksqd0InJsilHUWr3r6ahXjoaTO3KGHWV3dcg3BidLe66YzfQ
<-- END HTTP (466-byte body)
I/System.out: Gson fails to read a malformed JSON element
I/System.out: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $
import retrofit2.Call;
import retrofit2.http.Header;
import retrofit2.http.POST;
public interface UserClient {
@POST("token")
Call<User> getUser(@Header("Authorization") String autHeader);
}
please check it your api response is array of object or object of array according to you can arrange the pojo class